]> www.infradead.org Git - mtd-utils.git/commitdiff
ubi-utils: introduce ubinfo utility
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Sat, 22 Dec 2007 13:43:19 +0000 (15:43 +0200)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Sat, 22 Dec 2007 15:49:58 +0000 (17:49 +0200)
Add new handy UBI utility which prints various type of UBI information.

This commit also includes a lot of fixes and cleanups in libubi, and
other utilities. It was quite complex to separate this all out and
I figured that nobody anyway would really need this, and decided to
save my time for more useful things.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
ubi-utils/Makefile
ubi-utils/inc/libubi.h
ubi-utils/src/common.c
ubi-utils/src/common.h
ubi-utils/src/libubi.c
ubi-utils/src/libubi_int.h
ubi-utils/src/ubimkvol.c
ubi-utils/src/ubinfo.c [new file with mode: 0644]
ubi-utils/src/ubirmvol.c

index 1a3b2b98491a7da81da042d2a0153df213f44553..ee4956fc144734405eaa4da8f0ac581f14e46a68 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for ubi-utils
 #
 
-OPTFLAGS := -O2 -g -Wall
+OPTFLAGS := -O2 -Wall
 KERNELHDR := ../include
 DESTDIR := /usr/local
 SBINDIR=/usr/sbin
@@ -15,7 +15,7 @@ CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror \
 
 PERLPROGS = mkpfi ubicrc32.pl
 TARGETS = ubiupdatevol ubimkvol ubirmvol pfiflash pddcustomize ubimirror \
-       bin2nand nand2bin ubigen mkbootenv unubi pfi2bin ubicrc32
+       bin2nand nand2bin ubigen mkbootenv unubi pfi2bin ubicrc32 ubinfo
 
 vpath   %.c ./src
 
@@ -33,6 +33,9 @@ IGNORE=${wildcard .*.c.dep}
 clean:
        rm -rf *.o $(TARGETS) .*.c.dep
 
+ubinfo: ubinfo.o common.o libubi.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
 ubiupdatevol: ubiupdatevol.o error.o libubi.o
        $(CC) $(LDFLAGS) -o $@ $^
 
index d39c1b93ef13af9622e7c1f5cff65857b6a372f8..21be68a0f3f7de8523e7089a862e350b76fdc480 100644 (file)
@@ -40,7 +40,13 @@ typedef void * libubi_t;
 
 /**
  * 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;
@@ -52,11 +58,12 @@ struct ubi_mkvol_request
 
 /**
  * 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
+ * @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
 {
@@ -64,26 +71,29 @@ struct ubi_info
        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
- * @total_ebs        total number of eraseblocks on this UBI device
- * @avail_ebs        how many eraseblocks are not used and available for new
- *                   volumes
- * @total_bytes      @total_ebs * @eb_size
- * @avail_bytes      @avail_ebs * @eb_size
- * @bad_count        count of bad eraseblocks
- * @eb_size          size of UBI eraseblock
- * @max_ec           current highest erase counter value
- * @bad_rsvd         how many physical eraseblocks of the underlying flash
- *                   device are reserved for bad eraseblocks handling
- * @max_vol_count    maximum count of volumes on this UBI device
- * @min_io_size      minimum input/output size of the UBI device
+ * @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_ebs: total number of logical eraseblocks on this UBI device
+ * @avail_ebs: how many logical eraseblocks are not used and available for new
+ *             volumes
+ * @total_bytes: @total_ebs * @eb_size
+ * @avail_bytes: @avail_ebs * @eb_size
+ * @bad_count: count of bad physical eraseblocks
+ * @eb_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
 {
@@ -91,6 +101,8 @@ struct ubi_dev_info
        int vol_count;
        int lowest_vol_num;
        int highest_vol_num;
+       int major;
+       int minor;
        int total_ebs;
        int avail_ebs;
        long long total_bytes;
@@ -105,24 +117,31 @@ struct ubi_dev_info
 
 /**
  * struct ubi_vol_info - UBI volume information.
- *
- * @dev_num      UBI device number the volume resides on
- * @vol_id       ID of this volume
- * @type         volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
- * @alignment    alignemnt of this volume
- * @data_bytes   how many data bytes are stored on this volume (equivalent to
- *               @rsvd_bytes for dynamic volumes)
- * @rsvd_bytes   how many bytes are reserved for this volume
- * @rsvd_ebs     how many eraseblocks are reserved for this volume
- * @eb_size      logical eraseblock size of this volume (may be less then
- *               device's logical eraseblock size due to alignment)
- * @corrupted    the volume is corrupted if this flag is not zero
- * @name         volume name (null-terminated)
+ * @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_ebs: how many logical eraseblocks are reserved for this volume
+ * @eb_size: logical eraseblock size of this volume (may be less then
+ *           device's logical eraseblock size due to alignment)
+ * @corrupted: 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;
@@ -135,24 +154,21 @@ struct ubi_vol_info
 
 /**
  * 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
- *
+ * libubi_close - close UBI library.
  * @desc UBI library descriptor
  */
 void libubi_close(libubi_t desc);
 
 /**
  * ubi_get_info - get general UBI information.
- *
- * @info  pointer to the &struct ubi_info object to fill
- * @desc  UBI library descriptor
+ * @info: pointer to the &struct ubi_info object to fill
+ * @desc: UBI library descriptor
  *
  * This function fills the passed @info object with general UBI information and
  * returns %0 in case of success and %-1 in case of failure.
@@ -161,10 +177,9 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info);
 
 /**
  * ubi_mkvol - create an UBI volume.
- *
- * @desc  UBI library descriptor
- * @node  name of the UBI character device to create a volume at
- * @req   UBI volume creation request (defined at <mtd/ubi-user.h>)
+ * @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
@@ -174,10 +189,9 @@ 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
+ * @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.
@@ -186,23 +200,33 @@ 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
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device owning the volume which should be
+ *        re-sized
+ * @vol_id: volume ID to re-size
+ * @bytes: new volume size in bytes
  *
  * This function returns %0 in case of success and %-1 in case of error.
  */
 int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes);
 
 /**
- * ubi_get_dev_info - get UBI device information.
+ * ubi_node_type - test UBI node type.
+ * @desc: UBI library descriptor
+ * @node: the node to test
  *
- * @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 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.
@@ -212,10 +236,9 @@ int ubi_get_dev_info(libubi_t desc, const char *node,
 
 /**
  * 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
+ * @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.
@@ -224,10 +247,9 @@ 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
+ * @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.
@@ -237,11 +259,10 @@ int ubi_get_vol_info(libubi_t desc, const char *node,
 
 /**
  * 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
+ * @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.
@@ -251,10 +272,9 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
 
 /**
  * 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
+ * @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.
index 4a56128e281bf16c21a8d818c8a05eb99d7afb16..761d47df164923a127068c775e52634a8acbade8 100644 (file)
@@ -20,6 +20,7 @@
  * This file contains various common stuff used by UBI utilities.
  */
 
+#include <stdio.h>
 #include <string.h>
 
 /**
@@ -50,3 +51,37 @@ int ubiutils_get_multiplier(const char *str)
 
        return -1;
 }
+
+/**
+ * ubiutils_print_bytes - print bytes.
+ * @bytes: variable to print
+ * @bracket: whether brackets have to be put or not
+ *
+ * This is a helper function which prints amount of bytes in a human-readable
+ * form, i.e., it prints the exact amount of bytes following by the approximate
+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
+ * is.
+ */
+void ubiutils_print_bytes(long long bytes, int bracket)
+{
+       const char *p;
+
+       if (bracket)
+               p = " (";
+       else
+               p = ", ";
+
+       printf("%lld bytes", bytes);
+
+       if (bytes > 1024 * 1024 * 1024)
+               printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024));
+       else if (bytes > 1024 * 1024)
+               printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024));
+       else if (bytes > 1024)
+               printf("%s%.1f KiB", p, (double)bytes / 1024);
+       else
+               return;
+
+       if (bracket)
+               printf(")");
+}
index c20d3080462268929fe4fdae1e59c0c6520db92e..0e33dd1c65aaf762445bda55df38d73e848ad040 100644 (file)
 #ifndef __UBI_UTILS_COMMON_H__
 #define __UBI_UTILS_COMMON_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Maximum device node name length */
 #define MAX_NODE_LEN 255
 
 /* Error messages */
-#define errmsg(fmt, ...) do {                               \
-        fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \
+#define errmsg(fmt, ...) do {                                             \
+        fprintf(stderr, PROGRAM_NAME " error: " fmt "\n", ##__VA_ARGS__); \
 } while(0)
 
 /* Warnings */
-#define warnmsg(fmt, ...) do {                              \
-        fprintf(stderr, "Warning: " fmt "\n", ##__VA_ARGS__); \
+#define warnmsg(fmt, ...) do {                                              \
+        fprintf(stderr, PROGRAM_NAME " warning: " fmt "\n", ##__VA_ARGS__); \
 } while(0)
 
 int ubiutils_get_multiplier(const char *str);
+void ubiutils_print_bytes(long long bytes, int bracket);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* !__UBI_UTILS_COMMON_H__ */
index 4d2b725a2260590f89a31e7af0fc0c1c65c95c1e..ecc12b452c4a197d780dc8ff4a7fe589c8b731a2 100644 (file)
 #include "libubi.h"
 #include "libubi_int.h"
 
-libubi_t libubi_open(void)
+/**
+ * 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)
 {
-       int fd, version;
-       struct libubi *lib;
+       char *n;
+       int len1 = strlen(path);
+       int len2 = strlen(name);
 
-       lib = calloc(1, sizeof(struct libubi));
-       if (!lib)
+       n = malloc(len1 + len2 + 2);
+       if (!n) {
+               errmsg("cannot allocate %d bytes", len1 + len2 + 2);
+               perror("malloc");
                return NULL;
+       }
 
-       /* TODO: this must be discovered instead */
-       lib->sysfs = strdup("/sys");
-       if (!lib->sysfs)
-               goto error;
+       memcpy(n, path, len1);
+       if (n[len1 - 1] != '/')
+               n[len1++] = '/';
 
-       lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
-       if (!lib->sysfs_ubi)
-               goto error;
+       memcpy(n + len1, name, len2 + 1);
+       return n;
+}
 
-       /* Make sure UBI is present */
-       fd = open(lib->sysfs_ubi, O_RDONLY);
+/**
+ * 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)
-               goto error;
-       close(fd);
+               return -1;
 
-       lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
-       if (!lib->ubi_dev)
-               goto error;
+       rd = read(fd, buf, 50);
+       if (rd == -1) {
+               errmsg("cannot read \"%s\"", file);
+               perror("read");
+               goto out_error;
+       }
+       if (rd == 50) {
+               errmsg("contents of \"%s\" is too long", file);
+               errno = EINVAL;
+               goto out_error;
+       }
 
-       lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
-       if (!lib->ubi_version)
-               goto 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;
+       }
 
-       lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
-       if (!lib->dev_dev)
-               goto error;
+       if (*value < 0) {
+               errmsg("negative value %lld in \"%s\"", *value, file);
+               errno = EINVAL;
+               goto out_error;
+       }
 
-       lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
-       if (!lib->dev_avail_ebs)
-               goto error;
+       if (close(fd)) {
+               errmsg("close failed on \"%s\"", file);
+               perror("close");
+               return -1;
+       }
 
-       lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
-       if (!lib->dev_total_ebs)
-               goto error;
+       return 0;
 
-       lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
-       if (!lib->dev_bad_count)
-               goto error;
+out_error:
+       close(fd);
+       return -1;
+}
 
-       lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
-       if (!lib->dev_eb_size)
-               goto error;
+/**
+ * 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;
 
-       lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
-       if (!lib->dev_max_ec)
-               goto error;
+       if (read_positive_ll(file, &res))
+               return -1;
 
-       lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
-       if (!lib->dev_bad_rsvd)
-               goto error;
+       /* 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;
+       }
 
-       lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
-       if (!lib->dev_max_vols)
-               goto error;
+       *value = res;
+       return 0;
+}
 
-       lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE);
-       if (!lib->dev_min_io_size)
-               goto error;
+/**
+ * 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;
 
-       lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
-       if (!lib->ubi_vol)
-               goto error;
+       fd = open(file, O_RDONLY);
+       if (fd == -1)
+               return -1;
 
-       lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
-       if (!lib->vol_type)
-               goto error;
+       rd = read(fd, buf, buf_len);
+       if (rd == -1) {
+               errmsg("cannot read \"%s\"", file);
+               perror("read");
+               goto out_error;
+       }
 
-       lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
-       if (!lib->vol_dev)
-               goto error;
+       /* Make sure all data is read */
+       tmp1 = read(fd, &tmp, 1);
+       if (tmp1 == 1) {
+               errmsg("cannot read \"%s\"", file);
+               perror("read");
+               goto out_error;
+       }
+       if (tmp1) {
+               errmsg("file \"%s\" contains too much data (> %d bytes)",
+                      file, buf_len);
+               errno = EINVAL;
+               goto out_error;
+       }
 
-       lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
-       if (!lib->vol_alignment)
-               goto error;
+       if (close(fd)) {
+               errmsg("close failed on \"%s\"", file);
+               perror("close");
+               return -1;
+       }
 
-       lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
-       if (!lib->vol_data_bytes)
-               goto error;
+       return rd;
 
-       lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
-       if (!lib->vol_rsvd_ebs)
-               goto error;
+out_error:
+       close(fd);
+       return -1;
+}
 
-       lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
-       if (!lib->vol_eb_size)
-               goto error;
+/**
+ * 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];
 
-       lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
-       if (!lib->vol_corrupted)
-               goto error;
+       ret = read_data(file, buf, 50);
+       if (ret < 0)
+               return ret;
 
-       lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
-       if (!lib->vol_name)
-               goto error;
+       ret = sscanf(buf, "%d:%d\n", major, minor);
+       if (ret != 2) {
+               errmsg("\"%s\" does not have major:minor format", file);
+               errno = EINVAL;
+               return -1;
+       }
 
-       if (read_int(lib->ubi_version, &version))
-               goto error;
-       if (version != LIBUBI_UBI_VERSION) {
-               fprintf(stderr, "LIBUBI: this library was made for UBI version "
-                               "%d, but UBI version %d is detected\n",
-                       LIBUBI_UBI_VERSION, version);
-               goto error;
+       if (*major < 0 || *minor < 0) {
+               errmsg("bad major:minor %d:%d in \"%s\"",
+                      *major, *minor, file);
+               errno = EINVAL;
+               return -1;
        }
 
-       return lib;
+       return 0;
+}
 
-error:
-       free(lib->vol_corrupted);
-       free(lib->vol_eb_size);
-       free(lib->vol_rsvd_ebs);
-       free(lib->vol_data_bytes);
-       free(lib->vol_alignment);
-       free(lib->vol_dev);
-       free(lib->vol_type);
-       free(lib->ubi_vol);
-       free(lib->dev_min_io_size);
-       free(lib->dev_max_vols);
-       free(lib->dev_bad_rsvd);
-       free(lib->dev_max_ec);
-       free(lib->dev_eb_size);
-       free(lib->dev_bad_count);
-       free(lib->dev_total_ebs);
-       free(lib->dev_avail_ebs);
-       free(lib->dev_dev);
-       free(lib->ubi_version);
-       free(lib->ubi_dev);
-       free(lib->sysfs_ubi);
-       free(lib->sysfs);
-       free(lib);
-       return NULL;
+/**
+ * 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);
 }
 
-void libubi_close(libubi_t desc)
+/**
+ * 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)
 {
-       struct libubi *lib = (struct libubi *)desc;
+       char file[strlen(patt) + 100];
 
-       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_min_io_size);
-       free(lib->dev_max_vols);
-       free(lib->dev_bad_rsvd);
-       free(lib->dev_max_ec);
-       free(lib->dev_eb_size);
-       free(lib->dev_bad_count);
-       free(lib->dev_total_ebs);
-       free(lib->dev_avail_ebs);
-       free(lib->dev_dev);
-       free(lib->ubi_version);
-       free(lib->ubi_dev);
-       free(lib->sysfs_ubi);
-       free(lib->sysfs);
-       free(lib);
+       sprintf(file, patt, dev_num, vol_id);
+       return read_positive_int(file, value);
 }
 
-int ubi_get_info(libubi_t desc, struct ubi_info *info)
+/**
+ * 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)
 {
-       DIR *sysfs_ubi;
-       struct dirent *dirent;
-       struct libubi *lib = (struct libubi *)desc;
+       char file[strlen(patt) + 50];
 
-       memset(info, '\0', sizeof(struct ubi_info));
+       sprintf(file, patt, dev_num);
+       return read_positive_ll(file, value);
+}
 
-       /*
-        * We have to scan the UBI sysfs directory to identify how many UBI
-        * devices are present.
-        */
-       sysfs_ubi = opendir(lib->sysfs_ubi);
-       if (!sysfs_ubi)
-               return -1;
+/**
+ * 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];
 
-       info->lowest_dev_num = INT_MAX;
-       while ((dirent = readdir(sysfs_ubi))) {
-               char *name = &dirent->d_name[0];
-               int dev_num, ret;
+       sprintf(file, patt, dev_num, vol_id);
+       return read_positive_ll(file, value);
+}
 
-               ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num);
-               if (ret == 1) {
-                       info->dev_count += 1;
-                       if (dev_num > info->highest_dev_num)
-                               info->highest_dev_num = dev_num;
-                       if (dev_num < info->lowest_dev_num)
-                               info->lowest_dev_num = dev_num;
-               }
+/**
+ * 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);
+}
+
+/**
+ * dent_is_dir - check if a file is a directory.
+ * @dir: the base directory path of the file
+ * @name: file name
+ *
+ * This function returns %1 if file @name in directory @dir is a directoru, and
+ * %0 if not.
+ */
+static int dent_is_dir(const char *dir, const char *name)
+{
+       int ret;
+       struct stat st;
+       char full_path[strlen(dir) + strlen(name) + 2];
+
+       sprintf(full_path, "%s/%s", dir, name);
+       ret = lstat(full_path, &st);
+       if (ret) {
+               errmsg("lstat failed on \"%s\"", full_path);
+               perror("lstat");
+               return -1;
        }
 
-       if (info->lowest_dev_num == INT_MAX)
-               info->lowest_dev_num = 0;
+       return !!S_ISDIR(st.st_mode);
+}
 
-       if (read_int(lib->ubi_version, &info->version))
-               goto close;
+/**
+ * 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];
 
-       return closedir(sysfs_ubi);
+       sprintf(file, lib->dev_dev, dev_num);
+       return read_major(file, major, minor);
+}
 
-close:
-       closedir(sysfs_ubi);
-       return -1;
+/**
+ * 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);
 }
 
-int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
+/**
+ * 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)
 {
-       int fd, ret;
-       struct ubi_mkvol_req r;
-       size_t n;
+       struct stat st;
+       struct ubi_info info;
+       int i, fd, major, minor;
+       char file[strlen(lib->ubi_vol) + 100];
 
-       desc = desc;
-       r.vol_id = req->vol_id;
-       r.alignment = req->alignment;
-       r.bytes = req->bytes;
-       r.vol_type = req->vol_type;
+       if (lstat(node, &st))
+               return -1;
 
-       n = strlen(req->name);
-       if (n > UBI_MAX_VOLUME_NAME)
+       if (!S_ISCHR(st.st_mode)) {
+               errmsg("\"%s\" is not a character device", node);
+               errno = EINVAL;
                return -1;
+       }
 
-       strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1);
-       r.name_len = n;
+       major = major(st.st_rdev);
+       minor = minor(st.st_rdev);
 
-       fd = open(node, O_RDONLY);
-       if (fd == -1)
+       if (minor == 0) {
+               errmsg("\"%s\" is not a volume character device", node);
+               errno = -EINVAL;
                return -1;
+       }
 
-       ret = ioctl(fd, UBI_IOCMKVOL, &r);
-       if (!ret)
-               req->vol_id = r.vol_id;
+       if (ubi_get_info((libubi_t *)lib, &info))
+               return -1;
 
-       close(fd);
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+               int major1, minor1, ret;
 
-#ifdef UDEV_SETTLE_HACK
-       if (system("udevsettle") == -1)
+               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 = ENOENT;
                return -1;
-#endif
+       }
 
-       return ret;
+       /* Make sure this UBI volume exists */
+       sprintf(file, lib->ubi_vol, i, minor - 1);
+       fd = open(file, O_RDONLY);
+       if (fd == -1) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       *dev_num = i;
+       *vol_id = minor - 1;
+       return 0;
 }
 
-int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
+/**
+ * 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)
 {
-       int fd, ret;
+       struct stat stat;
+       struct ubi_info info;
+       int i, major, minor;
 
-       desc = desc;
-       fd = open(node, O_RDONLY);
-       if (fd == -1)
+       if (lstat(node, &stat))
                return -1;
 
-       ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
-       close(fd);
-
-#ifdef UDEV_SETTLE_HACK
-       if (system("udevsettle") == -1)
+       if (!S_ISCHR(stat.st_mode)) {
+               errmsg("\"%s\" is not a character device", node);
+               errno = EINVAL;
                return -1;
-#endif
+       }
 
-       return ret;
-}
+       major = major(stat.st_rdev);
+       minor = minor(stat.st_rdev);
 
-int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
-{
-       int fd, ret;
-       struct ubi_rsvol_req req;
+       if (minor != 0) {
+               errmsg("\"%s\" is not an UBI character device", node);
+               errno = -EINVAL;
+               return -1;
+       }
 
-       desc = desc;
-       fd = open(node, O_RDONLY);
-       if (fd == -1)
+       if (ubi_get_info((libubi_t *)lib, &info))
                return -1;
 
-       req.bytes = bytes;
-       req.vol_id = vol_id;
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+               int major1, minor1, ret;
 
-       ret = ioctl(fd, UBI_IOCRSVOL, &req);
-       close(fd);
-       return ret;
-}
+               ret = dev_get_major(lib, i, &major1, &minor1);
+               if (ret) {
+                       if (errno == ENOENT)
+                               continue;
+                       return -1;
+               }
 
-int ubi_update_start(libubi_t desc, int fd, long long bytes)
-{
-       desc = desc;
-       if (ioctl(fd, UBI_IOCVOLUP, &bytes))
-               return -1;
-       return 0;
+               if (major1 == major) {
+                       if (minor1 != 0) {
+                               errmsg("UBI character device minor number is "
+                                      "%d, but must be 0", minor1);
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       *dev_num = i;
+                       return 0;
+               }
+       }
+
+       errno = ENOENT;
+       return -1;
 }
 
-int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
+libubi_t libubi_open(void)
 {
-       int dev_num;
-       struct libubi *lib = (struct libubi *)desc;
+       int fd, version;
+       struct libubi *lib;
 
-       dev_num = find_dev_num(lib, node);
-       if (dev_num == -1)
-               return -1;
+       lib = calloc(1, sizeof(struct libubi));
+       if (!lib)
+               return NULL;
 
-       return ubi_get_dev_info1(desc, dev_num, info);
-}
+       /* TODO: this must be discovered instead */
+       lib->sysfs = strdup("/sys");
+       if (!lib->sysfs)
+               goto out_error;
 
-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;
+       lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL);
+       if (!lib->sysfs_ctrl)
+               goto out_error;
 
-       memset(info, '\0', sizeof(struct ubi_dev_info));
-       info->dev_num = dev_num;
+       lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV);
+       if (!lib->ctrl_dev)
+               goto out_error;
 
-       sysfs_ubi = opendir(lib->sysfs_ubi);
-       if (!sysfs_ubi)
-               return -1;
+       lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
+       if (!lib->sysfs_ubi)
+               goto out_error;
 
-       info->lowest_vol_num = INT_MAX;
-       while ((dirent = readdir(sysfs_ubi))) {
-               char *name = &dirent->d_name[0];
-               int vol_id, ret, devno;
+       /* 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;
+       }
 
-               ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id);
-               if (ret == 2 && devno == dev_num) {
-                       info->vol_count += 1;
-                       if (vol_id > info->highest_vol_num)
-                               info->highest_vol_num = vol_id;
-                       if (vol_id < info->lowest_vol_num)
-                               info->lowest_vol_num = vol_id;
-               }
+       if (close(fd)) {
+               errmsg("close failed on \"%s\"", lib->sysfs_ubi);
+               perror("close");
+               goto out_error;
        }
 
-       closedir(sysfs_ubi);
+       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->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;
 
-       if (info->lowest_vol_num == INT_MAX)
-               info->lowest_vol_num = 0;
+       lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
+       if (!lib->vol_name)
+               goto out_error;
 
-       if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs))
-               return -1;
-       if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs))
-               return -1;
-       if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
-               return -1;
-       if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size))
-               return -1;
-       if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
-               return -1;
-       if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
-               return -1;
-       if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
-               return -1;
-       if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
-               return -1;
+       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;
+       }
 
-       info->avail_bytes = info->avail_ebs * info->eb_size;
-       info->total_bytes = info->total_ebs * info->eb_size;
+       return lib;
 
-       return 0;
+out_error:
+       libubi_close((libubi_t)lib);
+       return NULL;
 }
 
-int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
+void libubi_close(libubi_t desc)
 {
-       int vol_id, dev_num;
        struct libubi *lib = (struct libubi *)desc;
 
-       dev_num = find_dev_num_vol(lib, node);
-       if (dev_num == -1)
-               return -1;
-
-       vol_id = find_vol_num(lib, dev_num, node);
-       if (vol_id == -1)
-               return -1;
-
-       return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+       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_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_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
-                     struct ubi_vol_info *info)
+int ubi_node_type(libubi_t desc, const char *node)
 {
-       int ret;
+       struct stat st;
+       struct ubi_info info;
+       int i, fd, major, minor;
        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;
+       char file[strlen(lib->ubi_vol) + 100];
 
-       ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50);
-       if (ret < 0)
+       if (lstat(node, &st))
                return -1;
 
-       if (strncmp(&buf[0], "static\n", ret) == 0)
-               info->type = UBI_STATIC_VOLUME;
-       else if (strncmp(&buf[0], "dynamic\n", ret) == 0)
-               info->type = UBI_DYNAMIC_VOLUME;
-       else {
-               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+       if (!S_ISCHR(st.st_mode)) {
+               errmsg("\"%s\" is not a character device", node);
                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_ebs);
-       if (ret)
-               return -1;
-       ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size);
-       if (ret)
-               return -1;
-       ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
-                          &info->corrupted);
-       if (ret)
-               return -1;
-       info->rsvd_bytes = info->eb_size * info->rsvd_ebs;
+       major = major(st.st_rdev);
+       minor = minor(st.st_rdev);
 
-       ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
-                           UBI_VOL_NAME_MAX + 2);
-       if (ret < 0)
+       if (ubi_get_info((libubi_t *)lib, &info))
                return -1;
 
-       info->name[ret - 1] = '\0';
-       return 0;
-}
-
-/**
- * read_int - read an 'int' value from a file.
- *
- * @file   the file to read from
- * @value  the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int read_int(const char *file, int *value)
-{
-       int fd, rd;
-       char buf[50];
-
-       fd = open(file, O_RDONLY);
-       if (fd == -1)
-               return -1;
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+               int major1, minor1, ret;
 
-       rd = read(fd, &buf[0], 50);
-       if (rd == -1)
-               goto error;
+               ret = dev_get_major(lib, i, &major1, &minor1);
+               if (ret) {
+                       if (errno == ENOENT)
+                               continue;
+                       return -1;
+               }
 
-       if (sscanf(&buf[0], "%d\n", value) != 1) {
-               /* This must be a UBI bug */
-               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-               errno = EINVAL;
-               goto error;
+               if (major1 == major)
+                       break;
        }
 
-       close(fd);
-       return 0;
-
-error:
-       close(fd);
-       return -1;
-}
-
-/**
- * dev_read_int - read an 'int' value from an UBI device's sysfs file.
- *
- * @patt     the file pattern to read from
- * @dev_num  UBI device number
- * @value    the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_int(const char *patt, int dev_num, int *value)
-{
-       int fd, rd;
-       char buf[50];
-       char file[strlen(patt) + 50];
-
-       sprintf(&file[0], patt, dev_num);
-       fd = open(&file[0], O_RDONLY);
-       if (fd == -1)
+       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;
+       }
 
-       rd = read(fd, &buf[0], 50);
-       if (rd == -1)
-               goto error;
+       if (minor == 0)
+               return 1;
 
-       if (sscanf(&buf[0], "%d\n", value) != 1) {
-               /* This must be a UBI bug */
-               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-               errno = EINVAL;
-               goto error;
+       /* 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;
        }
 
-       close(fd);
-       return 0;
-
-error:
-       close(fd);
-       return -1;
+       return 2;
 }
 
-/**
- * dev_read_ll - read a 'long long' value from an UBI device's sysfs file.
- *
- * @patt     the file pattern to read from
- * @dev_num  UBI device number
- * @value    the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_ll(const char *patt, int dev_num, long long *value)
+int ubi_get_info(libubi_t desc, struct ubi_info *info)
 {
-       int fd, rd;
-       char buf[50];
-       char file[strlen(patt) + 50];
+       DIR *sysfs_ubi;
+       struct dirent *dirent;
+       struct libubi *lib = (struct libubi *)desc;
 
-       sprintf(&file[0], patt, dev_num);
-       fd = open(&file[0], O_RDONLY);
-       if (fd == -1)
-               return -1;
+       memset(info, '\0', sizeof(struct ubi_info));
 
-       rd = read(fd, &buf[0], 50);
-       if (rd == -1)
-               goto error;
+       if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor))
+               return -1;
 
-       if (sscanf(&buf[0], "%lld\n", value) != 1) {
-               /* This must be a UBI bug */
-               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-               errno = EINVAL;
-               goto error;
+       /*
+        * 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) {
+               errmsg("cannot open %s", lib->sysfs_ubi);
+               perror("opendir");
+               return -1;
        }
 
-       close(fd);
-       return 0;
+       info->lowest_dev_num = INT_MAX;
+       while ((dirent = readdir(sysfs_ubi))) {
+               int dev_num, ret;
 
-error:
-       close(fd);
-       return -1;
-}
+               /*
+                * Make sure this direntry is a directory and not a symlink -
+                * Linux puts symlinks to UBI volumes on this UBI device to the
+                * same sysfs directory.
+                */
+               if (!dent_is_dir(lib->sysfs_ubi, dirent->d_name))
+                       continue;
 
-/**
- * dev_read_data - read data from an UBI device's sysfs file.
- *
- * @patt     the file pattern to read from
- * @dev_num  UBI device number
- * @buf      buffer to read data to
- * @buf_len  buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len)
-{
-       int fd, rd;
-       char file[strlen(patt) + 50];
+               ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT, &dev_num);
+               if (ret == 1) {
+                       info->dev_count += 1;
+                       if (dev_num > info->highest_dev_num)
+                               info->highest_dev_num = dev_num;
+                       if (dev_num < info->lowest_dev_num)
+                               info->lowest_dev_num = dev_num;
+               }
+       }
 
-       sprintf(&file[0], patt, dev_num);
-       fd = open(&file[0], O_RDONLY);
-       if (fd == -1)
-               return -1;
+       if (!dirent && errno) {
+               errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+               perror("readdir");
+               goto out_close;
+       }
 
-       rd = read(fd, buf, buf_len);
-       if (rd == -1) {
-               close(fd);
+       if (closedir(sysfs_ubi)) {
+               errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+               perror("closedir");
                return -1;
        }
 
-       close(fd);
-       return rd;
-}
-
-/**
- * vol_read_int - read an 'int' value from an UBI volume's sysfs file.
- *
- * @patt     the file pattern to read from
- * @dev_num  UBI device number
- * @vol_id   volume identifier
- * @value    the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
-{
-       int fd, rd;
-       char buf[50];
-       char file[strlen(patt) + 100];
+       if (info->lowest_dev_num == INT_MAX)
+               info->lowest_dev_num = 0;
 
-       sprintf(&file[0], patt, dev_num, vol_id);
-       fd = open(&file[0], O_RDONLY);
-       if (fd == -1)
+       if (read_positive_int(lib->ubi_version, &info->version))
                return -1;
 
-       rd = read(fd, &buf[0], 50);
-       if (rd == -1)
-               goto error;
-
-       if (sscanf(&buf[0], "%d\n", value) != 1) {
-               /* This must be a UBI bug */
-               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-               errno = EINVAL;
-               goto error;
-       }
-
-       close(fd);
        return 0;
 
-error:
-       close(fd);
+out_close:
+       closedir(sysfs_ubi);
        return -1;
 }
 
-/**
- * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file.
- *
- * @patt     the file pattern to read from
- * @dev_num  UBI device number
- * @vol_id   volume identifier
- * @value    the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_ll(const char *patt, int dev_num, int vol_id,
-                      long long *value)
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
 {
-       int fd, rd;
-       char buf[50];
-       char file[strlen(patt) + 100];
+       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;
 
-       sprintf(&file[0], patt, dev_num, vol_id);
-       fd = open(&file[0], O_RDONLY);
+       fd = open(node, O_RDONLY);
        if (fd == -1)
                return -1;
 
-       rd = read(fd, &buf[0], 50);
-       if (rd == -1)
-               goto error;
-
-       if (sscanf(&buf[0], "%lld\n", value) != 1) {
-               /* This must be a UBI bug */
-               fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-               errno = EINVAL;
-               goto error;
-       }
+       ret = ioctl(fd, UBI_IOCMKVOL, &r);
+       if (ret == 0)
+               req->vol_id = r.vol_id;
 
        close(fd);
-       return 0;
 
-error:
-       close(fd);
-       return -1;
+#ifdef UDEV_SETTLE_HACK
+       if (system("udevsettle") == -1)
+               return -1;
+#endif
+
+       return ret;
 }
 
-/**
- * vol_read_data - read data from an UBI volume's sysfs file.
- *
- * @patt     the file pattern to read from
- * @dev_num  UBI device number
- * @vol_id   volume identifier
- * @buf      buffer to read to
- * @buf_len  buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
-                        int buf_len)
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
 {
-       int fd, rd;
-       char file[strlen(patt) + 100];
+       int fd, ret;
 
-       sprintf(&file[0], patt, dev_num, vol_id);
-       fd = open(&file[0], O_RDONLY);
+       desc = desc;
+       fd = open(node, O_RDONLY);
        if (fd == -1)
                return -1;
 
-       rd = read(fd, buf, buf_len);
-       if (rd == -1) {
-               close(fd);
+       ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
+       close(fd);
+
+#ifdef UDEV_SETTLE_HACK
+       if (system("udevsettle") == -1)
                return -1;
-       }
+#endif
 
-       close(fd);
-       return rd;
+       return ret;
 }
 
-/**
- * mkpath - compose full path from 2 given components.
- *
- * @path  first component
- * @name  second component
- *
- * This function returns the resulting path in case of success and %NULL in
- * case of failure.
- */
-static char *mkpath(const char *path, const char *name)
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
 {
-       char *n;
-       int len1 = strlen(path);
-       int len2 = strlen(name);
+       int fd, ret;
+       struct ubi_rsvol_req req;
 
-       n = malloc(len1 + len2 + 2);
-       if (!n)
-               return NULL;
+               desc = desc;
+       fd = open(node, O_RDONLY);
+       if (fd == -1)
+               return -1;
 
-       memcpy(n, path, len1);
-       if (n[len1 - 1] != '/')
-               n[len1++] = '/';
+       req.bytes = bytes;
+       req.vol_id = vol_id;
 
-       memcpy(n + len1, name, len2 + 1);
-       return n;
+       ret = ioctl(fd, UBI_IOCRSVOL, &req);
+       close(fd);
+       return ret;
 }
 
-/**
- * find_dev_num - find UBI device number by its character device node.
- *
- * @lib   UBI library descriptor
- * @node  UBI character device node name
- *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
- */
-static int find_dev_num(struct libubi *lib, const char *node)
+int ubi_update_start(libubi_t desc, int fd, long long bytes)
 {
-       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;
+       desc = desc;
+       if (ioctl(fd, UBI_IOCVOLUP, &bytes))
                return -1;
-       }
+       return 0;
+}
 
-       major = major(stat.st_rdev);
-       minor = minor(stat.st_rdev);
+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;
 
-       if (minor != 0) {
-               errno = -EINVAL;
-               return -1;
-       }
+       memset(info, '\0', sizeof(struct ubi_dev_info));
+       info->dev_num = dev_num;
 
-       if (ubi_get_info((libubi_t *)lib, &info))
+       sysfs_ubi = opendir(lib->sysfs_ubi);
+       if (!sysfs_ubi)
                return -1;
 
-       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
-               int major1, minor1, ret;
-               char buf[50];
-
-               ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
-               if (ret < 0)
-                       return -1;
+       info->lowest_vol_num = INT_MAX;
+       while ((dirent = readdir(sysfs_ubi))) {
+               int vol_id, ret, devno;
 
-               ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
-               if (ret != 2) {
-                       fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-                       errno = EINVAL;
-                       return -1;
+               ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT, &devno, &vol_id);
+               if (ret == 2 && devno == dev_num) {
+                       info->vol_count += 1;
+                       if (vol_id > info->highest_vol_num)
+                               info->highest_vol_num = vol_id;
+                       if (vol_id < info->lowest_vol_num)
+                               info->lowest_vol_num = vol_id;
                }
-
-               if (minor1 == minor && major1 == major)
-                       return i;
        }
 
-       errno = ENOENT;
-       return -1;
-}
-
-/**
- * find_dev_num_vol - find UBI device number by volume character device node.
- *
- * @lib   UBI library descriptor
- * @node  UBI character device node name
- *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
- */
-static int find_dev_num_vol(struct libubi *lib, const char *node)
-{
-       struct stat stat;
-       struct ubi_info info;
-       int i, major;
-
-       if (lstat(node, &stat))
-               return -1;
+       if (!dirent && errno) {
+               errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+               perror("readdir");
+               goto out_close;
+       }
 
-       if (!S_ISCHR(stat.st_mode)) {
-               errno = EINVAL;
+       if (closedir(sysfs_ubi)) {
+               errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+               perror("closedir");
                return -1;
        }
 
-       major = major(stat.st_rdev);
+       if (info->lowest_vol_num == INT_MAX)
+               info->lowest_vol_num = 0;
 
-       if (minor(stat.st_rdev) == 0) {
-               errno = -EINVAL;
+       if (dev_get_major(lib, dev_num, &info->major, &info->minor))
                return -1;
-       }
 
-       if (ubi_get_info((libubi_t *)lib, &info))
+       if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs))
+               return -1;
+       if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs))
+               return -1;
+       if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
+               return -1;
+       if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size))
+               return -1;
+       if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
+               return -1;
+       if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
+               return -1;
+       if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
+               return -1;
+       if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
                return -1;
 
-       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
-               int major1, minor1, ret;
-               char buf[50];
-
-               ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
-               if (ret < 0)
-                       return -1;
-
-               ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
-               if (ret != 2) {
-                       fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-                       errno = EINVAL;
-                       return -1;
-               }
+       info->avail_bytes = info->avail_ebs * info->eb_size;
+       info->total_bytes = info->total_ebs * info->eb_size;
 
-               if (major1 == major)
-                       return i;
-       }
+       return 0;
 
-       errno = ENOENT;
+out_close:
+       closedir(sysfs_ubi);
        return -1;
 }
 
-/**
- * find_vol_num - find UBI volume number by its character device node.
- *
- * @lib      UBI library descriptor
- * @dev_num  UBI device number
- * @node     UBI volume character device node name
- *
- * This function returns positive UBI volume number in case of success and %-1
- * in case of failure.
- */
-static int find_vol_num(struct libubi *lib, int dev_num, const char *node)
+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
 {
-       struct stat stat;
-       struct ubi_dev_info info;
-       int i, major, minor;
+       int dev_num;
+       struct libubi *lib = (struct libubi *)desc;
 
-       if (lstat(node, &stat))
+       if (dev_node2num(lib, node, &dev_num))
                return -1;
 
-       if (!S_ISCHR(stat.st_mode)) {
-               errno = EINVAL;
+       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;
-       }
 
-       major = major(stat.st_rdev);
-       minor = minor(stat.st_rdev);
+       ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50);
+       if (ret < 0)
+               return -1;
 
-       if (minor == 0) {
-               errno = -EINVAL;
+       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;
        }
 
-       if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info))
+       ret = vol_read_int(lib->vol_alignment, dev_num, vol_id,
+                          &info->alignment);
+       if (ret)
+               return -1;
+       ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id,
+                         &info->data_bytes);
+       if (ret)
+               return -1;
+       ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_ebs);
+       if (ret)
+               return -1;
+       ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size);
+       if (ret)
+               return -1;
+       ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
+                          &info->corrupted);
+       if (ret)
                return -1;
+       info->rsvd_bytes = info->eb_size * info->rsvd_ebs;
 
-       for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) {
-               int major1, minor1, ret;
-               char buf[50];
+       ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
+                           UBI_VOL_NAME_MAX + 2);
+       if (ret < 0)
+               return -1;
 
-               ret = vol_read_data(lib->vol_dev,  dev_num, i, &buf[0], 50);
-               if (ret < 0)
-                       return -1;
+       info->name[ret - 1] = '\0';
+       return 0;
+}
 
-               ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
-               if (ret != 2) {
-                       fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
-                       errno = EINVAL;
-                       return -1;
-               }
+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 (minor1 == minor && major1 == major)
-                       return i;
-       }
+       if (vol_node2nums(lib, node, &dev_num, &vol_id))
+               return -1;
 
-       errno = ENOENT;
-       return -1;
+       return ubi_get_vol_info1(desc, dev_num, vol_id, info);
 }
index e68b79121cb5824ab1fde14b194932db3c9f0ad3..4c26eb5cb70be6a5b6ff8a8b6f6c8e0820a2ecfd 100644 (file)
 extern "C" {
 #endif
 
+/* Error messages */
+#define errmsg(fmt, ...) do {                                      \
+        fprintf(stderr, "libubi error: " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
 /*
- * UBI heavily makes use of the sysfs file system to interact with users-pace.
  * The below are pre-define UBI file and directory names.
+ *
+ * Note, older kernels put 'ubiX_Y' directories straight to '/sys/class/ubi/'.
+ * New kernels puts 'ubiX_Y' directories to '/sys/class/ubi/ubiX/', which is
+ * saner. And for compatibility reasons it also puts symlinks to 'ubiX_Y'
+ * directories to '/sys/class/ubi/'. For now libubi assumes old layout.
  */
 
 #define SYSFS_UBI         "class/ubi"
-#define UBI_DEV_NAME_PATT "ubi%d"
+#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 UBI_VOL_NAME_PATT "ubi%d_%d"
 #define DEV_AVAIL_EBS     "avail_eraseblocks"
 #define DEV_TOTAL_EBS     "total_eraseblocks"
 #define DEV_BAD_COUNT     "bad_peb_count"
@@ -45,6 +58,8 @@ extern "C" {
 #define DEV_MAX_RSVD      "reserved_for_bad"
 #define DEV_MAX_VOLS      "max_vol_count"
 #define DEV_MIN_IO_SIZE   "min_io_size"
+
+#define UBI_VOL_NAME_PATT "ubi%d_%d"
 #define VOL_TYPE          "type"
 #define VOL_DEV           "dev"
 #define VOL_ALIGNMENT     "alignment"
@@ -56,34 +71,37 @@ extern "C" {
 
 /**
  * libubi - UBI library description data structure.
- *
- * @sysfs            sysfs file system path
- * @sysfs_ubi        UBI directory in sysfs
- * @ubi_dev          UBI device sysfs directory pattern
- * @ubi_version      UBI version file sysfs path
- * @dev_dev          UBI device's major/minor numbers file pattern
- * @dev_avail_ebs    count of available eraseblocks sysfs path pattern
- * @dev_total_ebs    total eraseblocks count sysfs path pattern
- * @dev_bad_count    count of bad eraseblocks sysfs path pattern
- * @dev_eb_size      size of UBI device's eraseblocks sysfs path pattern
- * @dev_max_ec       maximum erase counter sysfs path pattern
- * @dev_bad_rsvd     count of physical eraseblock reserved for bad eraseblocks
- *                   handling
- * @dev_max_vols     maximum volumes number count sysfs path pattern
- * @dev_min_io_size  minimum I/O unit size sysfs path pattern
- * @ubi_vol          UBI volume sysfs directory pattern
- * @vol_type         volume type sysfs path pattern
- * @vol_dev          volume's major/minor numbers file pattern
- * @vol_alignment    volume alignment sysfs path pattern
- * @vol_data_bytes   volume data size sysfs path pattern
- * @vol_rsvd_ebs     volume reserved size sysfs path pattern
- * @vol_eb_size      volume eraseblock size sysfs path pattern
- * @vol_corrupted    volume corruption flag sysfs path pattern
- * @vol_name         volume name sysfs path pattern
+ * @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;
@@ -108,20 +126,6 @@ struct libubi
        char *vol_max_count;
 };
 
-static int read_int(const char *file, int *value);
-static int dev_read_int(const char *patt, int dev_num, int *value);
-static int dev_read_ll(const char *patt, int dev_num, long long *value);
-static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len);
-static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value);
-static int vol_read_ll(const char *patt, int dev_num, int vol_id,
-                      long long *value);
-static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
-                        int buf_len);
-static char *mkpath(const char *path, const char *name);
-static int find_dev_num(struct libubi *lib, const char *node);
-static int find_dev_num_vol(struct libubi *lib, const char *node);
-static int find_vol_num(struct libubi *lib, int dev_num, const char *node);
-
 #ifdef __cplusplus
 }
 #endif
index 454e6fe80716c99209d245da22294a50bd0c7e73..488dd172b7ece4cca075d574f04cd2914a594a7f 100644 (file)
@@ -30,7 +30,6 @@
 #include <string.h>
 #include <errno.h>
 
-#include <config.h>
 #include <libubi.h>
 #include "common.h"
 
@@ -39,7 +38,6 @@
 
 /* The variables below is set by command line arguments */
 struct args {
-       int devn;
        int vol_id;
        int vol_type;
        long long bytes;
@@ -47,13 +45,12 @@ struct args {
        int alignment;
        char *name;
        int nlen;
-       char node[MAX_NODE_LEN + 1];
+       char node[MAX_NODE_LEN + 2];
        int maxavs;
 };
 
 static struct args myargs = {
        .vol_type = UBI_DYNAMIC_VOLUME,
-       .devn = -1,
        .bytes = -1,
        .lebs = -1,
        .alignment = 1,
@@ -83,15 +80,14 @@ static const char *optionsstr =
 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>] [--devn=<devn>] [--vol_id=<volume ID>]\n"
-"\t\t\t[--name=<name>] [--size=<bytes>] [--lebs=<LEBs>]\n"
-"\t\t\t[--type=<static|dynamic>] [--help] [--version] [--maxavsize]\n\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 = "devn",      .has_arg = 1, .flag = NULL, .val = 'd' },
        { .name = "vol_id",    .has_arg = 1, .flag = NULL, .val = 'n' },
        { .name = "name",      .has_arg = 1, .flag = NULL, .val = 'N' },
        { .name = "size",      .has_arg = 1, .flag = NULL, .val = 's' },
@@ -110,8 +106,7 @@ static int parse_opt(int argc, char * const argv[], struct args *args)
        while (1) {
                int key;
 
-               key = getopt_long(argc, argv, "a:d:n:N:s:S:t:hVm",
-                                 long_options, NULL);
+               key = getopt_long(argc, argv, "a:n:N:s:S:t:hVm", long_options, NULL);
                if (key == -1)
                        break;
 
@@ -161,20 +156,6 @@ static int parse_opt(int argc, char * const argv[], struct args *args)
                        }
                        break;
 
-               case 'd':
-                       args->devn = strtoul(optarg, &endp, 0);
-                       if (*endp != '\0' || endp == optarg || args->devn < 0) {
-                               errmsg("bad UBI device number: \"%s\"", optarg);
-                               return -1;
-                       }
-
-                       warnmsg("'-d' and '--devn' options are deprecated and will be "
-                               "removed. Specify UBI device node name instead!\n"
-                               "Example: " PROGRAM_NAME " /dev/ubi0, instead of "
-                               PROGRAM_NAME " -d 0");
-                       sprintf(args->node, "/dev/ubi%d", args->devn);
-                       break;
-
                case 'n':
                        args->vol_id = strtoul(optarg, &endp, 0);
                        if (*endp != '\0' || endp == optarg || args->vol_id < 0) {
@@ -215,7 +196,7 @@ static int parse_opt(int argc, char * const argv[], struct args *args)
        return 0;
 }
 
-static int param_sanity_check(struct args *args, libubi_t libubi)
+static int param_sanity_check(struct args *args)
 {
        int len;
 
@@ -225,7 +206,7 @@ static int param_sanity_check(struct args *args, libubi_t libubi)
                return -1;
        }
 
-       if (args->bytes == -1 && !args->maxavs && !args->lebs) {
+       if (args->bytes == -1 && !args->maxavs && args->lebs == -1) {
                errmsg("volume size was not specified (use -h for help)");
                return -1;
        }
@@ -242,23 +223,6 @@ static int param_sanity_check(struct args *args, libubi_t libubi)
                return -1;
        }
 
-       if (args->devn != -1) {
-               int err;
-               struct ubi_info ubi;
-
-               err = ubi_get_info(libubi, &ubi);
-               if (err) {
-                       errmsg("cannot get UBI information");
-                       perror("ubi_get_info");
-                       return -1;
-               }
-
-               if (args->devn >= ubi.dev_count) {
-                       errmsg("UBI device %d does not exist", args->devn);
-                       return -1;
-               }
-       }
-
        len = strlen(args->name);
        if (len > UBI_MAX_VOLUME_NAME) {
                errmsg("too long name (%d symbols), max is %d",
@@ -287,27 +251,37 @@ int main(int argc, char * const argv[])
                return -1;
        }
 
-       strncpy(myargs.node, argv[1], MAX_NODE_LEN);
+       if (argv[1][0] == '-') {
+               errmsg("UBI device was not specified (use -h for help)");
+               return -1;
+       }
+
+       if (argv[2][0] != '-') {
+               errmsg("incorrect arguments, use -h for help");
+               return -1;
+       }
+
+       strncpy(myargs.node, argv[1], MAX_NODE_LEN + 1);
 
        err = parse_opt(argc, (char **)argv, &myargs);
        if (err)
                return err;
 
        libubi = libubi_open();
-       if (libubi == NULL) {
+       if (!libubi) {
                errmsg("cannot open libubi");
                perror("libubi_open");
                return -1;
        }
 
-       err = param_sanity_check(&myargs, libubi);
+       err = param_sanity_check(&myargs);
        if (err)
                goto out_libubi;
 
        err = ubi_get_dev_info(libubi, myargs.node, &dev_info);
        if (err) {
-               errmsg("cannot get information about UBI device number %d (%s)",
-                      myargs.devn, myargs.node);
+               errmsg("cannot get information about UBI device number %s",
+                      myargs.node);
                perror("ubi_get_dev_info");
                goto out_libubi;
        }
@@ -346,19 +320,11 @@ int main(int argc, char * const argv[])
                goto out_libubi;
        }
 
-       printf("Volume ID is %d, size %lld LEBs (%lld bytes, ",
-              vol_info.vol_id, vol_info.rsvd_bytes / vol_info.eb_size,
-              vol_info.rsvd_bytes);
-
-       if (vol_info.rsvd_bytes > 1024 * 1024 * 1024)
-               printf("%.1f GiB)", (double)vol_info.rsvd_bytes / (1024 * 1024 * 1024));
-       else if (vol_info.rsvd_bytes > 1024 * 1024)
-               printf("%.1f MiB)", (double)vol_info.rsvd_bytes / (1024 * 1024));
-       else
-               printf("%.1f KiB)", (double)vol_info.rsvd_bytes / 1024);
-
-       printf(" LEB size is %d bytes (%.1f KiB), %s volume, name \"%s\", alignment %d\n",
-              vol_info.eb_size, (double)vol_info.eb_size / 1024,
+       printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_ebs);
+       ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+       printf("), LEB size ");
+       ubiutils_print_bytes(vol_info.eb_size, 1);
+       printf(", %s volume, name \"%s\", alignment %d\n",
               req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
               vol_info.name, vol_info.alignment);
 
diff --git a/ubi-utils/src/ubinfo.c b/ubi-utils/src/ubinfo.c
new file mode 100644 (file)
index 0000000..358f208
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * 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
+ *
+ * Author: Artem Bityutskiy
+ */
+
+/*
+ * An utility to get UBI information.
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME    "ubinfo"
+
+/* The variables below is set by command line arguments */
+struct args {
+       int devn;
+       int vol_id;
+       int all;
+       char node[MAX_NODE_LEN + 2];
+       int node_given;
+};
+
+static struct args myargs = {
+       .vol_id = -1,
+       .devn = -1,
+       .all = 0,
+       .node_given = 0,
+};
+
+static const char *doc = "Version " PROGRAM_VERSION "\n"
+       PROGRAM_NAME " - a tool to 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[], struct args *args)
+{
+       char *endp;
+
+       while (1) {
+               int key;
+
+               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) {
+                               errmsg("bad volume ID: " "\"%s\"", optarg);
+                               return -1;
+                       }
+                       break;
+
+               case 'd':
+                       args->devn = strtoul(optarg, &endp, 0);
+                       if (*endp != '\0' || endp == optarg || args->devn < 0) {
+                               errmsg("bad UBI device number: \"%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(0);
+
+               case 'V':
+                       fprintf(stderr, "%s\n", PROGRAM_VERSION);
+                       exit(0);
+
+               case ':':
+                       errmsg("parameter is missing");
+                       return -1;
+
+               default:
+                       fprintf(stderr, "Use -h for help\n");
+                       exit(-1);
+               }
+       }
+
+       return 0;
+}
+
+static int translate_dev(libubi_t libubi, const char *node)
+{
+       int err;
+
+       if (strlen(node) > MAX_NODE_LEN) {
+               errmsg("too long device node name: \"%s\" (%d characters), max. is %d",
+                      node, strlen(node), MAX_NODE_LEN);
+               return -1;
+       }
+
+       err = ubi_node_type(libubi, node);
+       if (err == -1) {
+               if (errno) {
+                       errmsg("unrecognized device node \"%s\"", node);
+                       perror("ubi_node_type");
+                       return -1;
+               }
+               errmsg("\"%s\" does not correspond to any UBI device or volume",
+                      node);
+               return -1;
+       }
+
+       if (err == 1) {
+               struct ubi_dev_info dev_info;
+
+               err = ubi_get_dev_info(libubi, node, &dev_info);
+               if (err) {
+                       errmsg("cannot get information about UBI device \"%s\"",
+                              node);
+                       perror("ubi_get_dev_info");
+                       return -1;
+               }
+
+               myargs.devn = dev_info.dev_num;
+       } else {
+               struct ubi_vol_info vol_info;
+
+               err = ubi_get_vol_info(libubi, node, &vol_info);
+               if (err) {
+                       errmsg("cannot get information about UBI volume \"%s\"",
+                              node);
+                       perror("ubi_get_vol_info");
+                       return -1;
+               }
+
+               if (myargs.vol_id != -1) {
+                       errmsg("both volume character device node (\"%s\") and "
+                              "volume ID (%d) are specify, use only one of them"
+                              "(use -h for help)", node, myargs.vol_id);
+                       return -1;
+               }
+
+               myargs.devn = vol_info.dev_num;
+               myargs.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) {
+               errmsg("cannot get information about UBI volume %d on ubi%d",
+                      vol_id, dev_num);
+               perror("ubi_get_vol_info1");
+               return -1;
+       }
+
+       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_ebs);
+       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) {
+               errmsg("cannot get information about UBI device %d", dev_num);
+               perror("ubi_get_dev_info1");
+               return -1;
+       }
+
+       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.eb_size);
+
+       printf("Total amount of logical eraseblocks:     %d (", dev_info.total_ebs);
+       ubiutils_print_bytes(dev_info.total_bytes, 0);
+       printf(")\n");
+
+       printf("Amount of available logical eraseblocks: %d", dev_info.avail_ebs);
+       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;
+
+                       errmsg("libubi failed to probe volume %d on ubi%d",
+                              i, dev_info.dev_num);
+                       perror("ubi_get_vol_info1");
+                       return -1;
+               }
+
+               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;
+
+                       errmsg("libubi failed to probe volume %d on ubi%d",
+                              i, dev_info.dev_num);
+                       perror("ubi_get_vol_info1");
+                       return -1;
+               }
+               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) {
+               errmsg("cannot get UBI information");
+               perror("ubi_get_info");
+               return -1;
+       }
+
+       printf("UBI version:                    %d\n", ubi_info.version);
+       printf("Count of UBI devices:           %d\n", ubi_info.dev_count);
+       printf("UBI control device major/minor: %d:%d\n",
+              ubi_info.ctrl_major, ubi_info.ctrl_minor);
+
+       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;
+
+                       errmsg("libubi failed to probe UBI device %d", i);
+                       perror("ubi_get_dev_info1");
+                       return -1;
+               }
+
+               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;
+
+                       errmsg("libubi failed to probe UBI device %d", i);
+                       perror("ubi_get_dev_info1");
+                       return -1;
+               }
+               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;
+
+       if (argc > 1 && argv[1][0] != '-') {
+               strncpy(myargs.node, argv[1], MAX_NODE_LEN + 1);
+               myargs.node_given = 1;
+       }
+
+       if (argc > 2 && argv[2][0] != '-') {
+               errmsg("incorrect arguments, use -h for help");
+               return -1;
+       }
+
+       err = parse_opt(argc, argv, &myargs);
+       if (err)
+               return -1;
+
+       if (argc > 1 && !myargs.node_given && myargs.devn != -1) {
+               errmsg("specify either device number or node file (use -h for help)");
+               return -1;
+       }
+
+       libubi = libubi_open();
+       if (libubi == NULL) {
+               errmsg("cannot open libubi");
+               perror("libubi_open");
+               return -1;
+       }
+
+       if (myargs.node_given) {
+               /*
+                * A character device was specified, translate this into UBI
+                * device number and volume ID.
+                */
+               err = translate_dev(libubi, myargs.node);
+               if (err)
+                       goto out_libubi;
+       }
+
+       if (myargs.vol_id != -1 && myargs.devn == -1) {
+               errmsg("volume ID is specified, but UBI device number is not "
+                      "(use -h for help)\n");
+               goto out_libubi;
+       }
+
+       if (myargs.devn != -1 && myargs.vol_id != -1) {
+               print_vol_info(libubi, myargs.devn, myargs.vol_id);
+               goto out;
+       }
+
+       if (myargs.devn == -1 && myargs.vol_id == -1)
+               err = print_general_info(libubi, myargs.all);
+       else if (myargs.devn != -1 && myargs.vol_id == -1)
+               err = print_dev_info(libubi, myargs.devn, myargs.all);
+
+       if (err)
+               goto out_libubi;
+
+out:
+       libubi_close(libubi);
+       return 0;
+
+out_libubi:
+       libubi_close(libubi);
+       return -1;
+}
index b6fb8efb95ecb405523acfff62b62ed4a7ba00b3..e9a1b41eaad59a2787d240351205e08811cbbfc5 100644 (file)
@@ -30,7 +30,6 @@
 #include <string.h>
 #include <errno.h>
 
-#include <config.h>
 #include <libubi.h>
 #include "common.h"
 
 
 /* The variables below is set by command line arguments */
 struct args {
-       int devn;
        int vol_id;
-       char node[MAX_NODE_LEN + 1];
+       char node[MAX_NODE_LEN + 2];
 };
 
 static struct args myargs = {
-       .devn = -1,
        .vol_id = -1,
 };
 
-static int param_sanity_check(struct args *args, libubi_t libubi);
-
 static const char *doc = "Version: " PROGRAM_VERSION "\n"
        PROGRAM_NAME " - a tool to remove UBI volumes.";
 
@@ -65,7 +60,6 @@ static const char *usage =
 "         to the node file /dev/ubi0.";
 
 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 = "help",    .has_arg = 0, .flag = NULL, .val = 'h' },
        { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
@@ -79,26 +73,12 @@ static int parse_opt(int argc, char * const argv[], struct args *args)
        while (1) {
                int key;
 
-               key = getopt_long(argc, argv, "d:n:hV", long_options, NULL);
+               key = getopt_long(argc, argv, "n: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) {
-                               errmsg("bad UBI device number: \"%s\"", optarg);
-                               return -1;
-                       }
-
-                       warnmsg("'-d' and '--devn' options are deprecated and will be "
-                               "removed. Specify UBI device node name instead!\n"
-                               "Example: " PROGRAM_NAME " /dev/ubi0, instead of "
-                               PROGRAM_NAME " -d 0");
-                       sprintf(args->node, "/dev/ubi%d", args->devn);
-                       break;
-
                case 'n':
                        args->vol_id = strtoul(optarg, &endp, 0);
                        if (*endp != '\0' || endp == optarg || args->vol_id < 0) {
@@ -132,10 +112,8 @@ static int parse_opt(int argc, char * const argv[], struct args *args)
        return -1;
 }
 
-static int param_sanity_check(struct args *args, libubi_t libubi)
+static int param_sanity_check(struct args *args)
 {
-       int err;
-
        if (strlen(args->node) > MAX_NODE_LEN) {
                errmsg("too long device node name: \"%s\" (%d characters), max. is %d",
                       args->node, strlen(args->node), MAX_NODE_LEN);
@@ -147,22 +125,6 @@ static int param_sanity_check(struct args *args, libubi_t libubi)
                return -1;
        }
 
-       if (args->devn != -1) {
-               struct ubi_info ubi;
-
-               err = ubi_get_info(libubi, &ubi);
-               if (err) {
-                       errmsg("cannot get UBI information");
-                       perror("ubi_get_info");
-                       return -1;
-               }
-
-               if (args->devn >= ubi.dev_count) {
-                       errmsg("UBI device %d does not exist", args->devn);
-                       return -1;
-               }
-       }
-
        return 0;
 }
 
@@ -171,11 +133,7 @@ int main(int argc, char * const argv[])
        int err;
        libubi_t libubi;
 
-       strncpy(myargs.node, argv[1], MAX_NODE_LEN);
-
-       err = parse_opt(argc, argv, &myargs);
-       if (err)
-               return -1;
+       strncpy(myargs.node, argv[1], MAX_NODE_LEN + 1);
 
        if (argc < 2) {
                errmsg("UBI device name was not specified (use -h for help)");
@@ -187,6 +145,20 @@ int main(int argc, char * const argv[])
                return -1;
        }
 
+       if (argv[1][0] == '-') {
+               errmsg("UBI device was not specified (use -h for help)");
+               return -1;
+       }
+
+       if (argv[2][0] != '-') {
+               errmsg("incorrect arguments, use -h for help");
+               return -1;
+       }
+
+       err = parse_opt(argc, argv, &myargs);
+       if (err)
+               return -1;
+
        libubi = libubi_open();
        if (libubi == NULL) {
                errmsg("cannot open libubi");
@@ -194,7 +166,7 @@ int main(int argc, char * const argv[])
                return -1;
        }
 
-       err = param_sanity_check(&myargs, libubi);
+       err = param_sanity_check(&myargs);
        if (err)
                goto out_libubi;