]> www.infradead.org Git - mtd-utils.git/commitdiff
ubi-utils: add sysfs interface support and new tool
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Sun, 26 Apr 2009 06:01:12 +0000 (09:01 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Mon, 11 May 2009 09:05:50 +0000 (12:05 +0300)
This large commit makes several things.

1. Switches libmtd to use the new sysfs interface
2. Implements new handy 'mtdinfo' utility
3. Does minore amendmends in libubi and some ubi-tools.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
ubi-utils/.gitignore
ubi-utils/Makefile
ubi-utils/include/libmtd.h
ubi-utils/src/libmtd.c
ubi-utils/src/libmtd_int.h [new file with mode: 0644]
ubi-utils/src/libmtd_legacy.c [new file with mode: 0644]
ubi-utils/src/libubi.c
ubi-utils/src/mtdinfo.c [new file with mode: 0644]
ubi-utils/src/ubiformat.c
ubi-utils/src/ubinfo.c

index 4155cd1bcf26cca17267d9a0b46bff951129f423..66e766cfb9749af4a818e110f2e6e1d5efc53997 100644 (file)
@@ -8,3 +8,4 @@
 /ubirename
 /ubirmvol
 /ubiupdatevol
+/mtdinfo
index dcff7e3775ece59da7792c344805fdbc1d703113..b5388ec541632c851df3c1b2c906e57340d97b8e 100644 (file)
@@ -6,12 +6,12 @@ KERNELHDR := ../include
 
 SUBDIRS = old-utils
 
-#CFLAGS += -Werror
+# CFLAGS += -Werror
 CPPFLAGS += -Iinclude -Isrc -I$(KERNELHDR)
 
 LIBS = libubi libmtd libubigen libiniparser libscan
 TARGETS = ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \
-          ubidetach ubinize ubiformat ubirename
+          ubidetach ubinize ubiformat ubirename mtdinfo
 
 VPATH = src
 
@@ -30,13 +30,17 @@ $(BUILDDIR)/ubinize: $(addprefix $(BUILDDIR)/,\
        ubinize.o common.o crc32.o libiniparser.a libubigen.a)
 #      $(CC) $(CFLAGS) $(filter %.o, $^) -L. -liniparser -lubigen -o $@
 
+$(BUILDDIR)/mtdinfo: $(addprefix $(BUILDDIR)/,\
+       libmtd.a libubigen.a crc32.o common.o)
+#      $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lmtd -lubigen -o $@
+
 $(BUILDDIR)/ubiformat: $(addprefix $(BUILDDIR)/,\
        ubiformat.o common.o crc32.o libmtd.a libscan.a libubi.a libubigen.a)
 #      $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lmtd -lscan -lubi -lubigen -o $@
 
 $(BUILDDIR)/libubi.a: $(BUILDDIR)/libubi.o
 
-$(BUILDDIR)/libmtd.a: $(BUILDDIR)/libmtd.o
+$(BUILDDIR)/libmtd.a: $(BUILDDIR)/libmtd.o $(BUILDDIR)/libmtd_legacy.o
 
 $(BUILDDIR)/libubigen.a: $(BUILDDIR)/libubigen.o
 
index 6a93e5f197f817242fc508062d1496b6ddfa3b66..8d5bc4f074fa108986969f44357e3590d038258d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2008, 2009 Nokia Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 extern "C" {
 #endif
 
+/* Maximum MTD device name length */
+#define MTD_NAME_MAX 127
 /* Maximum MTD device type string length */
 #define MTD_TYPE_MAX 64
 
+/* MTD library descriptor */
+typedef void * libmtd_t;
+
+/**
+ * @dev_count: count of MTD devices in system
+ * @lowest_dev_num: lowest MTD device number
+ * @highest_dev_num: highest MTD device number
+ * @sysfs_supported: non-zero if sysfs is supported by MTD
+ */
+struct mtd_info
+{
+       int dev_count;
+       int lowest_dev_num;
+       int highest_dev_num;
+       unsigned int sysfs_supported:1;
+};
+
 /**
  * struct mtd_dev_info - information about an MTD device.
  * @dev_num: MTD device number
@@ -37,11 +56,14 @@ extern "C" {
  * @minor: minor number of corresponding character device
  * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
  * @type_str: static R/O flash type string
+ * @name: device name
  * @size: device size in bytes
  * @eb_cnt: count of eraseblocks
  * @eb_size: eraseblock size
  * @min_io_size: minimum input/output unit size
  * @subpage_size: sub-page size
+ * @oob_size: OOB size (zero if the device does not have OOB area)
+ * @region_cnt: count of additional erase regions
  * @writable: zero if the device is read-only
  * @bb_allowed: non-zero if the MTD device may have bad eraseblocks
  */
@@ -51,26 +73,69 @@ struct mtd_dev_info
        int major;
        int minor;
        int type;
-       const char type_str[MTD_TYPE_MAX];
+       const char type_str[MTD_TYPE_MAX + 1];
+       const char name[MTD_NAME_MAX + 1];
        long long size;
        int eb_cnt;
        int eb_size;
        int min_io_size;
        int subpage_size;
+       int oob_size;
+       int region_cnt;
        unsigned int writable:1;
        unsigned int bb_allowed:1;
 };
 
+/**
+ * libmtd_open - open MTD library.
+ *
+ * This function initializes and opens the MTD library and returns MTD library
+ * descriptor in case of success and %NULL in case of failure. In case of
+ * failure, errno contains zero if MTD is not present in the system, or
+ * contains the error code if a real error happened.
+ */
+libmtd_t libmtd_open(void);
+
+/**
+ * libmtd_close - close MTD library.
+ * @desc: MTD library descriptor
+ */
+void libmtd_close(libmtd_t desc);
+
+/**
+ * mtd_get_info - get general MTD information.
+ * @desc: MTD library descriptor
+ * @info: the MTD device information is returned here
+ *
+ * This function fills the passed @info object with general MTD information and
+ * returns %0 in case of success and %-1 in case of failure. If MTD subsystem is
+ * not present in the system, errno is set to @ENODEV.
+ */
+int mtd_get_info(libmtd_t desc, struct mtd_info *info);
+
 /**
  * mtd_get_dev_info - get information about an MTD device.
+ * @desc: MTD library descriptor
  * @node: name of the MTD device node
  * @mtd: the MTD device information is returned here
  *
  * This function gets information about MTD device defined by the @node device
  * node file and saves this information in the @mtd object. Returns %0 in case
- * of success and %-1 in case of failure.
+ * of success and %-1 in case of failure. If MTD subsystem is not present in the
+ * system, or the MTD device does not exist, errno is set to @ENODEV.
  */
-int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd);
+int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd);
+
+/**
+ * mtd_get_dev_info1 - get information about an MTD device.
+ * @desc: MTD library descriptor
+ * @dev_num: MTD device number to fetch information about
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is identical to 'mtd_get_dev_info()' except that it accepts
+ * MTD device number, not MTD character device.
+ */
+int mtd_get_dev_info1(libmtd_t desc, int dev_num, struct mtd_dev_info *mtd);
 
 /**
  * mtd_erase - erase an eraseblock.
@@ -78,7 +143,7 @@ int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd);
  * @fd: MTD device node file descriptor
  * @eb: eraseblock to erase
  *
- * This function erases eraseblock @eb of MTD device decribed by @fd. Returns
+ * This function erases eraseblock @eb of MTD device described by @fd. Returns
  * %0 in case of success and %-1 in case of failure.
  */
 int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb);
@@ -137,6 +202,17 @@ int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
 int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
              void *buf, int len);
 
+/**
+ * mtd_probe_node - test MTD node.
+ * @desc: MTD library descriptor
+ * @node: the node to test
+ *
+ * This function tests whether @node is an MTD device node and returns %1 if it
+ * is, and %-1 if it is not (errno is ENODEV in this case) or if an error
+ * occurred.
+ */
+int mtd_probe_node(libmtd_t desc, const char *node);
+
 #ifdef __cplusplus
 }
 #endif
index faa958f0e00d86325f98bc3b6b8fa0f5a3b70430..046beea6ebdca728de78e5c44565f06c209ba600 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2009 Nokia Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * MTD library.
  */
 
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
-#include <unistd.h>
-#include <fcntl.h>
-
 #include <mtd/mtd-user.h>
+
 #include <libmtd.h>
+#include "libmtd_int.h"
 #include "common.h"
 
-#define PROGRAM_NAME "libmtd"
-#define MTD_DEV_MAJOR 90
+/**
+ * mkpath - compose full path from 2 given components.
+ * @path: the first component
+ * @name: the second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+       char *n;
+       int len1 = strlen(path);
+       int len2 = strlen(name);
+
+       n = malloc(len1 + len2 + 2);
+       if (!n) {
+               sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2);
+               return NULL;
+       }
+
+       memcpy(n, path, len1);
+       if (n[len1 - 1] != '/')
+               n[len1++] = '/';
+
+       memcpy(n + len1, name, len2 + 1);
+       return n;
+}
+
+/**
+ * read_data - read data from a file.
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure. Note, if the file contains more then @buf_len bytes of
+ * date, this function fails with %EINVAL error code.
+ */
+static int read_data(const char *file, void *buf, int buf_len)
+{
+       int fd, rd, tmp, tmp1;
+
+       fd = open(file, O_RDONLY);
+       if (fd == -1)
+               return -1;
+
+       rd = read(fd, buf, buf_len);
+       if (rd == -1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+
+       /* Make sure all data is read */
+       tmp1 = read(fd, &tmp, 1);
+       if (tmp1 == 1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+       if (tmp1) {
+               errmsg("file \"%s\" contains too much data (> %d bytes)",
+                      file, buf_len);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (close(fd)) {
+               sys_errmsg("close failed on \"%s\"", file);
+               return -1;
+       }
+
+       return rd;
+
+out_error:
+       close(fd);
+       return -1;
+}
+
+/**
+ * read_major - read major and minor numbers from a file.
+ * @file: name of the file to read from
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns % in case of success, and %-1 in case of failure.
+ */
+static int read_major(const char *file, int *major, int *minor)
+{
+       int ret;
+       char buf[50];
+
+       ret = read_data(file, buf, 50);
+       if (ret < 0)
+               return ret;
+
+       ret = sscanf(buf, "%d:%d\n", major, minor);
+       if (ret != 2) {
+               errno = EINVAL;
+               return errmsg("\"%s\" does not have major:minor format", file);
+       }
+
+       if (*major < 0 || *minor < 0) {
+               errno = EINVAL;
+               return errmsg("bad major:minor %d:%d in \"%s\"",
+                             *major, *minor, file);
+       }
+
+       return 0;
+}
+
+/**
+ * dev_get_major - get major and minor numbers of an MTD device.
+ * @lib: libmtd descriptor
+ * @dev_num: MTD device number
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of success and %-1 in case of failure.
+ */
+static int dev_get_major(struct libmtd *lib, int dev_num, int *major, int *minor)
+{
+       char file[strlen(lib->mtd_dev) + 50];
+
+       sprintf(file, lib->mtd_dev, dev_num);
+       return read_major(file, major, minor);
+}
 
-int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd)
+/**
+ * dev_read_data - read data from an MTD device's sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: MTD device number
+ * @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 dev_read_data(const char *patt, int dev_num, void *buf, int buf_len)
+{
+       char file[strlen(patt) + 100];
+
+       sprintf(file, patt, dev_num);
+       return read_data(file, buf, buf_len);
+}
+
+/**
+ * read_hex_ll - read a hex '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 hexadecimal
+ * '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_hex_ll(const char *file, long long *value)
+{
+       int fd, rd;
+       char buf[50];
+
+       fd = open(file, O_RDONLY);
+       if (fd == -1)
+               return -1;
+
+       rd = read(fd, buf, 50);
+       if (rd == -1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+       if (rd == 50) {
+               errmsg("contents of \"%s\" is too long", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (sscanf(buf, "%llx\n", value) != 1) {
+               errmsg("cannot read integer from \"%s\"\n", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (*value < 0) {
+               errmsg("negative value %lld in \"%s\"", *value, file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (close(fd))
+               return sys_errmsg("close failed on \"%s\"", file);
+
+       return 0;
+
+out_error:
+       close(fd);
+       return -1;
+}
+
+/**
+ * read_pos_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_pos_ll(const char *file, long long *value)
+{
+       int fd, rd;
+       char buf[50];
+
+       fd = open(file, O_RDONLY);
+       if (fd == -1)
+               return -1;
+
+       rd = read(fd, buf, 50);
+       if (rd == -1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+       if (rd == 50) {
+               errmsg("contents of \"%s\" is too long", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (sscanf(buf, "%lld\n", value) != 1) {
+               errmsg("cannot read integer from \"%s\"\n", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (*value < 0) {
+               errmsg("negative value %lld in \"%s\"", *value, file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (close(fd))
+               return sys_errmsg("close failed on \"%s\"", file);
+
+       return 0;
+
+out_error:
+       close(fd);
+       return -1;
+}
+
+/**
+ * read_hex_int - read an 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_pos_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_hex_int(const char *file, int *value)
+{
+       long long res;
+
+       if (read_hex_ll(file, &res))
+               return -1;
+
+       /* Make sure the value has correct range */
+       if (res > INT_MAX || res < INT_MIN) {
+               errmsg("value %lld read from file \"%s\" is out of range",
+                      res, file);
+               errno = EINVAL;
+               return -1;
+       }
+
+       *value = res;
+       return 0;
+}
+
+/**
+ * read_pos_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_pos_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_pos_int(const char *file, int *value)
+{
+       long long res;
+
+       if (read_pos_ll(file, &res))
+               return -1;
+
+       /* Make sure the value is not too big */
+       if (res > INT_MAX) {
+               errmsg("value %lld read from file \"%s\" is out of range",
+                      res, file);
+               errno = EINVAL;
+               return -1;
+       }
+
+       *value = res;
+       return 0;
+}
+
+/**
+ * dev_read_hex_int - read an hex 'int' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: MTD 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_hex_int(const char *patt, int dev_num, int *value)
+{
+       char file[strlen(patt) + 50];
+
+       sprintf(file, patt, dev_num);
+       return read_hex_int(file, value);
+}
+
+/**
+ * dev_read_pos_int - read a positive 'int' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: MTD 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_pos_int(const char *patt, int dev_num, int *value)
+{
+       char file[strlen(patt) + 50];
+
+       sprintf(file, patt, dev_num);
+       return read_pos_int(file, value);
+}
+
+/**
+ * dev_read_pos_ll - read a positive 'long long' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: MTD 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_pos_ll(const char *patt, int dev_num, long long *value)
+{
+       char file[strlen(patt) + 50];
+
+       sprintf(file, patt, dev_num);
+       return read_pos_ll(file, value);
+}
+
+/**
+ * type_str2int - convert MTD device type to integer.
+ * @str: MTD device type string to convert
+ *
+ * This function converts MTD device type string @str, read from sysfs, into an
+ * integer.
+ */
+static int type_str2int(const char *str)
+{
+       if (!strcmp(str, "nand"))
+               return MTD_NANDFLASH;
+       if (!strcmp(str, "nor"))
+               return MTD_NORFLASH;
+       if (!strcmp(str, "rom"))
+               return MTD_ROM;
+       if (!strcmp(str, "absent"))
+               return MTD_ABSENT;
+       if (!strcmp(str, "dataflash"))
+               return MTD_DATAFLASH;
+       if (!strcmp(str, "ram"))
+               return MTD_RAM;
+       if (!strcmp(str, "ubi"))
+               return MTD_UBIVOLUME;
+       return -1;
+}
+
+/**
+ * dev_node2num - find UBI device number by its character device node.
+ * @lib: MTD library descriptor
+ * @node: name of the MTD device node
+ * @dev_num: MTD device number is returned here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_node2num(struct libmtd *lib, const char *node, int *dev_num)
 {
        struct stat st;
-       struct mtd_info_user ui;
-       int fd, ret;
-       loff_t offs = 0;
+       int i, major, minor;
+       struct mtd_info info;
 
        if (stat(node, &st))
-               return sys_errmsg("cannot open \"%s\"", node);
+               return sys_errmsg("cannot get information about \"%s\"", node);
 
        if (!S_ISCHR(st.st_mode)) {
+               errmsg("\"%s\" is not a character device", node);
                errno = EINVAL;
-               return errmsg("\"%s\" is not a character device", node);
+               return -1;
        }
 
-       mtd->major = major(st.st_rdev);
-       mtd->minor = minor(st.st_rdev);
+       major = major(st.st_rdev);
+       minor = minor(st.st_rdev);
 
-       if (mtd->major != MTD_DEV_MAJOR) {
-               errno = EINVAL;
-               return errmsg("\"%s\" has major number %d, MTD devices have "
-                             "major %d", node, mtd->major, MTD_DEV_MAJOR);
+       if (mtd_get_info((libmtd_t *)lib, &info))
+               return -1;
+
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+               int major1, minor1, ret;
+
+               ret = dev_get_major(lib, i, &major1, &minor1);
+               if (ret) {
+                       if (errno == ENOENT)
+                               continue;
+                       if (!errno)
+                               break;
+                       return -1;
+               }
+
+               if (major1 == major && minor1 == minor) {
+                       errno = 0;
+                       *dev_num = i;
+                       return 0;
+               }
        }
 
-       mtd->dev_num = mtd->minor / 2;
-       mtd->writable = !(mtd->minor & 1);
+       errno = ENODEV;
+       return -1;
+}
 
-       fd = open(node, O_RDWR);
-       if (fd == -1)
-               return sys_errmsg("cannot open \"%s\"", node);
+libmtd_t libmtd_open(void)
+{
+       int fd;
+       struct libmtd *lib;
+
+       lib = calloc(1, sizeof(struct libmtd));
+       if (!lib)
+               return NULL;
+
+       lib->sysfs_mtd = mkpath("/sys", SYSFS_MTD);
+       if (!lib->sysfs_mtd)
+               goto out_error;
+
+       lib->mtd = mkpath(lib->sysfs_mtd, MTD_NAME_PATT);
+       if (!lib->mtd)
+               goto out_error;
+
+       /* Make sure MTD is recent enough and supports sysfs */
+       fd = open(lib->sysfs_mtd, O_RDONLY);
+       if (fd == -1) {
+               free(lib->mtd);
+               free(lib->sysfs_mtd);
+               if (errno != ENOENT || legacy_libmtd_open()) {
+                       free(lib);
+                       return NULL;
+               }
+               lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL;
+               return lib;
+       }
 
-       if (ioctl(fd, MEMGETINFO, &ui)) {
-               sys_errmsg("MEMGETINFO ioctl request failed");
-               goto out_close;
+       if (close(fd)) {
+               sys_errmsg("close failed on \"%s\"", lib->sysfs_mtd);
+               goto out_error;
        }
 
-       ret = ioctl(fd, MEMGETBADBLOCK, &offs);
-       if (ret == -1) {
-               if (errno != EOPNOTSUPP) {
-                       sys_errmsg("MEMGETBADBLOCK ioctl failed");
-                       goto out_close;
+       lib->mtd_name = mkpath(lib->mtd, MTD_NAME);
+       if (!lib->mtd_name)
+               goto out_error;
+
+       lib->mtd_dev = mkpath(lib->mtd, MTD_DEV);
+       if (!lib->mtd_dev)
+               goto out_error;
+
+       lib->mtd_type = mkpath(lib->mtd, MTD_TYPE);
+       if (!lib->mtd_type)
+               goto out_error;
+
+       lib->mtd_eb_size = mkpath(lib->mtd, MTD_EB_SIZE);
+       if (!lib->mtd_eb_size)
+               goto out_error;
+
+       lib->mtd_size = mkpath(lib->mtd, MTD_SIZE);
+       if (!lib->mtd_size)
+               goto out_error;
+
+       lib->mtd_min_io_size = mkpath(lib->mtd, MTD_MIN_IO_SIZE);
+       if (!lib->mtd_min_io_size)
+               goto out_error;
+
+       lib->mtd_subpage_size = mkpath(lib->mtd, MTD_SUBPAGE_SIZE);
+       if (!lib->mtd_subpage_size)
+               goto out_error;
+
+       lib->mtd_oob_size = mkpath(lib->mtd, MTD_OOB_SIZE);
+       if (!lib->mtd_oob_size)
+               goto out_error;
+
+       lib->mtd_region_cnt = mkpath(lib->mtd, MTD_REGION_CNT);
+       if (!lib->mtd_region_cnt)
+               goto out_error;
+
+       lib->mtd_flags = mkpath(lib->mtd, MTD_FLAGS);
+       if (!lib->mtd_flags)
+               goto out_error;
+
+       lib->sysfs_supported = 1;
+       return lib;
+
+out_error:
+       libmtd_close((libmtd_t)lib);
+       return NULL;
+}
+
+void libmtd_close(libmtd_t desc)
+{
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       free(lib->mtd_flags);
+       free(lib->mtd_region_cnt);
+       free(lib->mtd_oob_size);
+       free(lib->mtd_subpage_size);
+       free(lib->mtd_min_io_size);
+       free(lib->mtd_size);
+       free(lib->mtd_eb_size);
+       free(lib->mtd_type);
+       free(lib->mtd_dev);
+       free(lib->mtd_name);
+       free(lib->mtd);
+       free(lib->sysfs_mtd);
+       free(lib);
+}
+
+int mtd_get_info(libmtd_t desc, struct mtd_info *info)
+{
+       DIR *sysfs_mtd;
+       struct dirent *dirent;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       memset(info, '\0', sizeof(struct mtd_info));
+
+       if (!lib->sysfs_supported)
+               return legacy_mtd_get_info(info);
+
+       info->sysfs_supported = 1;
+
+       /*
+        * We have to scan the MTD sysfs directory to identify how many MTD
+        * devices are present.
+        */
+       sysfs_mtd = opendir(lib->sysfs_mtd);
+       if (!sysfs_mtd) {
+               if (errno == ENOENT) {
+                       errno = ENODEV;
+                       return -1;
                }
-               errno = 0;
-               mtd->bb_allowed = 0;
-       } else
-               mtd->bb_allowed = 1;
-
-       mtd->type = ui.type;
-       mtd->size = ui.size;
-       mtd->eb_size = ui.erasesize;
-       mtd->min_io_size = ui.writesize;
-
-       if (mtd->min_io_size <= 0) {
-               errmsg("mtd%d (%s) has insane min. I/O unit size %d",
-                      mtd->dev_num, node, mtd->min_io_size);
-               goto out_close;
+               return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd);
        }
-       if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
-               errmsg("mtd%d (%s) has insane eraseblock size %d",
-                      mtd->dev_num, node, mtd->eb_size);
-               goto out_close;
+
+       info->lowest_dev_num = INT_MAX;
+       while (1) {
+               int dev_num, ret;
+               char tmp_buf[256];
+
+               errno = 0;
+               dirent = readdir(sysfs_mtd);
+               if (!dirent)
+                       break;
+
+               if (strlen(dirent->d_name) >= 255) {
+                       errmsg("invalid entry in %s: \"%s\"",
+                              lib->sysfs_mtd, dirent->d_name);
+                       errno = EINVAL;
+                       goto out_close;
+               }
+
+               ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s",
+                            &dev_num, tmp_buf);
+               if (ret == 1) {
+                       info->dev_count += 1;
+                       if (dev_num > info->highest_dev_num)
+                               info->highest_dev_num = dev_num;
+                       if (dev_num < info->lowest_dev_num)
+                               info->lowest_dev_num = dev_num;
+               }
        }
-       if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
-               errmsg("mtd%d (%s) has insane size %lld",
-                      mtd->dev_num, node, mtd->size);
+
+       if (!dirent && errno) {
+               sys_errmsg("readdir failed on \"%s\"", lib->sysfs_mtd);
                goto out_close;
        }
-       mtd->eb_cnt = mtd->size / mtd->eb_size;
 
-       switch(mtd->type) {
-       case MTD_ABSENT:
-               errmsg("mtd%d (%s) is removable and is not present",
-                      mtd->dev_num, node);
-               goto out_close;
-       case MTD_RAM:
-               strcpy(mtd->type_str, "RAM-based");
-               break;
-       case MTD_ROM:
-               strcpy(mtd->type_str, "ROM");
-               break;
-       case MTD_NORFLASH:
-               strcpy(mtd->type_str, "NOR");
-               break;
-       case MTD_NANDFLASH:
-               strcpy(mtd->type_str, "NAND");
-               break;
-       case MTD_DATAFLASH:
-               strcpy(mtd->type_str, "DataFlash");
-               break;
-       case MTD_UBIVOLUME:
-               strcpy(mtd->type_str, "UBI-emulated MTD");
-               break;
-       default:
-               strcpy(mtd->type_str, "Unknown flash type");
-               break;
-       }
-
-       if (ui.flags & MTD_WRITEABLE)
-               mtd->writable = 1;
+       if (closedir(sysfs_mtd))
+               return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd);
+
+       if (info->lowest_dev_num == INT_MAX)
+               info->lowest_dev_num = 0;
 
-       close(fd);
        return 0;
 
 out_close:
-       close(fd);
+       closedir(sysfs_mtd);
        return -1;
 }
 
+int mtd_get_dev_info1(libmtd_t desc, int dev_num, struct mtd_dev_info *mtd)
+{
+       int ret;
+       struct stat st;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       memset(mtd, '\0', sizeof(struct mtd_dev_info));
+       mtd->dev_num = dev_num;
+
+       if (!lib->sysfs_supported)
+               return legacy_get_dev_info1(dev_num, mtd);
+       else {
+               char file[strlen(lib->mtd) + 10];
+
+               sprintf(file, lib->mtd, dev_num);
+               if (stat(file, &st)) {
+                       if (errno == ENOENT)
+                               errno = ENODEV;
+                       return -1;
+               }
+       }
+
+       if (dev_get_major(lib, dev_num, &mtd->major, &mtd->minor))
+               return -1;
+
+       ret = dev_read_data(lib->mtd_name, dev_num, &mtd->name,
+                           MTD_NAME_MAX);
+       if (ret < 0)
+               return -1;
+       ((char *)mtd->name)[ret - 1] = '\0';
+
+       ret = dev_read_data(lib->mtd_type, dev_num, &mtd->type_str,
+                           MTD_TYPE_MAX);
+       if (ret < 0)
+               return -1;
+       ((char *)mtd->type_str)[ret - 1] = '\0';
+
+       if (dev_read_pos_int(lib->mtd_eb_size, dev_num, &mtd->eb_size))
+               return -1;
+       if (dev_read_pos_ll(lib->mtd_size, dev_num, &mtd->size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_min_io_size, dev_num, &mtd->min_io_size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_subpage_size, dev_num, &mtd->subpage_size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_oob_size, dev_num, &mtd->oob_size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_region_cnt, dev_num, &mtd->region_cnt))
+               return -1;
+       if (dev_read_hex_int(lib->mtd_flags, dev_num, &ret))
+               return -1;
+       mtd->writable = !!(ret & MTD_WRITEABLE);
+
+       mtd->eb_cnt = mtd->size / mtd->eb_size;
+       mtd->type = type_str2int(mtd->type_str);
+       mtd->bb_allowed = !!(mtd->type == MTD_NANDFLASH);
+
+       return 0;
+}
+
+int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd)
+{
+       int dev_num;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       if (!lib->sysfs_supported)
+               return legacy_get_dev_info(node, mtd);
+
+       if (dev_node2num(lib, node, &dev_num))
+               return -1;
+
+       return mtd_get_dev_info1(desc, dev_num, mtd);
+}
+
 int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb)
 {
        struct erase_info_user ei;
@@ -252,7 +822,7 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
                errno = EINVAL;
                return -1;
        }
-#if 0
+
        if (offs % mtd->subpage_size) {
                errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
                       offs, mtd->dev_num, mtd->subpage_size);
@@ -265,7 +835,6 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
                errno = EINVAL;
                return -1;
        }
-#endif
 
        /* Seek to the beginning of the eraseblock */
        seek = (off_t)eb * mtd->eb_size + offs;
@@ -280,3 +849,48 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
 
        return 0;
 }
+
+int mtd_probe_node(libmtd_t desc, const char *node)
+{
+       struct stat st;
+       struct mtd_info info;
+       int i, major, minor;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       if (stat(node, &st))
+               return sys_errmsg("cannot get information about \"%s\"", node);
+
+       if (!S_ISCHR(st.st_mode)) {
+               errmsg("\"%s\" is not a character device", node);
+               errno = EINVAL;
+               return -1;
+       }
+
+       major = major(st.st_rdev);
+       minor = minor(st.st_rdev);
+
+       if (mtd_get_info((libmtd_t *)lib, &info))
+               return -1;
+
+       if (!lib->sysfs_supported)
+               return 0;
+
+       for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+               int major1, minor1, ret;
+
+               ret = dev_get_major(lib, i, &major1, &minor1);
+               if (ret) {
+                       if (errno == ENOENT)
+                               continue;
+                       if (!errno)
+                               break;
+                       return -1;
+               }
+
+               if (major1 == major && minor1 == minor)
+                       return 1;
+       }
+
+       errno = 0;
+       return -1;
+}
diff --git a/ubi-utils/src/libmtd_int.h b/ubi-utils/src/libmtd_int.h
new file mode 100644 (file)
index 0000000..7de4b42
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#ifndef __LIBMTD_INT_H__
+#define __LIBMTD_INT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PROGRAM_NAME "libmtd"
+
+#define SYSFS_MTD        "class/mtd"
+#define MTD_NAME_PATT    "mtd%d"
+#define MTD_DEV          "dev"
+#define MTD_NAME         "name"
+#define MTD_TYPE         "type"
+#define MTD_EB_SIZE      "erasesize"
+#define MTD_SIZE         "size"
+#define MTD_MIN_IO_SIZE  "writesize"
+#define MTD_SUBPAGE_SIZE "subpagesize"
+#define MTD_OOB_SIZE     "oobsize"
+#define MTD_REGION_CNT   "numeraseregions"
+#define MTD_FLAGS        "flags"
+
+/**
+ * libmtd - MTD library description data structure.
+ * @sysfs_mtd: MTD directory in sysfs
+ * @mtd: MTD device sysfs directory pattern
+ * @mtd_dev: MTD device major/minor numbers file pattern
+ * @mtd_name: MTD device name file pattern
+ * @mtd_type: MTD device type file pattern
+ * @mtd_eb_size: MTD device eraseblock size file pattern
+ * @mtd_size: MTD device size file pattern
+ * @mtd_min_io_size: minimum I/O unit size file pattern
+ * @mtd_subpage_size: sub-page size file pattern
+ * @mtd_oob_size: MTD device OOB size file pattern
+ * @mtd_region_cnt: count of additional erase regions file pattern
+ * @mtd_flags: MTD device flags file pattern
+ * @sysfs_supported: non-zero if sysfs is supported by MTD
+ */
+struct libmtd
+{
+       char *sysfs_mtd;
+       char *mtd;
+       char *mtd_dev;
+       char *mtd_name;
+       char *mtd_type;
+       char *mtd_eb_size;
+       char *mtd_size;
+       char *mtd_min_io_size;
+       char *mtd_subpage_size;
+       char *mtd_oob_size;
+       char *mtd_region_cnt;
+       char *mtd_flags;
+       unsigned int sysfs_supported:1;
+};
+
+int legacy_libmtd_open(void);
+int legacy_mtd_get_info(struct mtd_info *info);
+int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd);
+int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBMTD_INT_H__ */
diff --git a/ubi-utils/src/libmtd_legacy.c b/ubi-utils/src/libmtd_legacy.c
new file mode 100644 (file)
index 0000000..cd474b1
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * This file  is part of the MTD library. Implements pre-2.6.30 kernels support,
+ * where MTD did not have sysfs interface. The main limitation of the old
+ * kernels was that the sub-page size was not exported to user-space, so it was
+ * not possible to get sub-page size.
+ */
+
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include <libmtd.h>
+#include "libmtd_int.h"
+#include "common.h"
+
+#define MTD_PROC_FILE "/proc/mtd"
+#define MTD_DEV_PATT  "/dev/mtd%d"
+#define MTD_DEV_MAJOR 90
+
+#define PROC_MTD_FIRST     "dev:    size   erasesize  name\n"
+#define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1)
+#define PROC_MTD_MAX_LEN   4096
+#define PROC_MTD_PATT      "mtd%d: %llx %x"
+
+/**
+ * struct proc_parse_info - /proc/mtd parsing information.
+ * @dev_num: MTD device number
+ * @size: device size
+ * @eb_size: eraseblock size
+ * @name: device name
+ * @buf: contents of /proc/mtd
+ * @data_size: how much data was read into @buf
+ * @pos: next string in @buf to parse
+ */
+struct proc_parse_info
+{
+       int dev_num;
+       long long size;
+       char name[MTD_NAME_MAX + 1];
+       int eb_size;
+       char *buf;
+       int data_size;
+       char *next;
+};
+
+static int proc_parse_start(struct proc_parse_info *pi)
+{
+       int fd, ret;
+
+       fd = open(MTD_PROC_FILE, O_RDONLY);
+       if (fd == -1)
+               return -1;
+
+       pi->buf = malloc(PROC_MTD_MAX_LEN);
+       if (!pi->buf) {
+               sys_errmsg("cannot allocate %d bytes of memory",
+                          PROC_MTD_MAX_LEN);
+               goto out_close;
+       }
+
+       ret = read(fd, pi->buf, PROC_MTD_MAX_LEN);
+       if (ret == -1) {
+               sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
+               goto out_free;
+       }
+
+       if (ret < PROC_MTD_FIRST_LEN ||
+           memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) {
+               errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE,
+                      PROC_MTD_FIRST);
+               goto out_free;
+       }
+
+       pi->data_size = ret;
+       pi->next = pi->buf + PROC_MTD_FIRST_LEN;
+
+       close(fd);
+       return 0;
+
+out_free:
+       free(pi->buf);
+out_close:
+       close(fd);
+       return -1;
+}
+
+static int proc_parse_next(struct proc_parse_info *pi)
+{
+       int ret, len, pos = pi->next - pi->buf;
+       char *p, *p1;
+
+       if (pos >= pi->data_size) {
+               free(pi->buf);
+               return 0;
+       }
+
+       ret = sscanf(pi->next, PROC_MTD_PATT, &pi->dev_num, &pi->size,
+                    &pi->eb_size);
+       if (ret != 3)
+               return errmsg("\"%s\" pattern not found", PROC_MTD_PATT);
+
+       p = memchr(pi->next, '\"', pi->data_size - pos);
+       if (!p)
+               return errmsg("opening \" not fount");
+       p += 1;
+       pos = p - pi->buf;
+       if (pos >= pi->data_size)
+               return errmsg("opening \" not fount");
+
+       p1 = memchr(p, '\"', pi->data_size - pos);
+       if (!p1)
+               return errmsg("closing \" not fount");
+       pos = p1 - pi->buf;
+       if (pos >= pi->data_size)
+               return errmsg("closing \" not fount");
+
+       len = p1 - p;
+       if (len > MTD_NAME_MAX)
+               return errmsg("too long mtd%d device name", pi->dev_num);
+
+       memcpy(pi->name, p, len);
+       pi->name[len] = '\0';
+
+       if (p1[1] != '\n')
+               return errmsg("opening \"\n\" not fount");
+       pi->next = p1 + 2;
+       return 1;
+}
+
+/**
+ * legacy_libmtd_open - legacy version of 'libmtd_open()'.
+ *
+ * This function is just checks that MTD is present in the system. Returns
+ * zero in case of success and %-1 in case of failure. In case of failure,
+ * errno contains zero if MTD is not present in the system, or contains the
+ * error code if a real error happened. This is similar to the 'libmtd_open()'
+ * return conventions.
+ */
+int legacy_libmtd_open(void)
+{
+       int fd;
+
+       fd = open(MTD_PROC_FILE, O_RDONLY);
+       if (fd == -1) {
+               if (errno == ENOENT)
+                       errno = 0;
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+/**
+ * legacy_mtd_get_info - legacy version of 'mtd_get_info()'.
+ * @info: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_info()' and has the same conventions.
+ */
+int legacy_mtd_get_info(struct mtd_info *info)
+{
+       int ret;
+       struct proc_parse_info pi;
+
+       ret = proc_parse_start(&pi);
+       if (ret)
+               return -1;
+
+       info->lowest_dev_num = INT_MAX;
+       while (proc_parse_next(&pi)) {
+               info->dev_count += 1;
+               if (pi.dev_num > info->highest_dev_num)
+                       info->highest_dev_num = pi.dev_num;
+               if (pi.dev_num < info->lowest_dev_num)
+                       info->lowest_dev_num = pi.dev_num;
+       }
+
+       return 0;
+}
+
+/**
+ * legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'.
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_dev_info()' and has the same
+ * conventions.
+ */
+int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd)
+{
+       struct stat st;
+       struct mtd_info_user ui;
+       int fd, ret;
+       loff_t offs = 0;
+       struct proc_parse_info pi;
+
+       if (stat(node, &st))
+               return sys_errmsg("cannot open \"%s\"", node);
+
+       if (!S_ISCHR(st.st_mode)) {
+               errno = EINVAL;
+               return errmsg("\"%s\" is not a character device", node);
+       }
+
+       memset(mtd, '\0', sizeof(struct mtd_dev_info));
+       mtd->major = major(st.st_rdev);
+       mtd->minor = minor(st.st_rdev);
+
+       if (mtd->major != MTD_DEV_MAJOR) {
+               errno = EINVAL;
+               return errmsg("\"%s\" has major number %d, MTD devices have "
+                             "major %d", node, mtd->major, MTD_DEV_MAJOR);
+       }
+
+       mtd->dev_num = mtd->minor / 2;
+
+       fd = open(node, O_RDWR);
+       if (fd == -1)
+               return sys_errmsg("cannot open \"%s\"", node);
+
+       if (ioctl(fd, MEMGETINFO, &ui)) {
+               sys_errmsg("MEMGETINFO ioctl request failed");
+               goto out_close;
+       }
+
+       ret = ioctl(fd, MEMGETBADBLOCK, &offs);
+       if (ret == -1) {
+               if (errno != EOPNOTSUPP) {
+                       sys_errmsg("MEMGETBADBLOCK ioctl failed");
+                       goto out_close;
+               }
+               errno = 0;
+               mtd->bb_allowed = 0;
+       } else
+               mtd->bb_allowed = 1;
+
+       mtd->type = ui.type;
+       mtd->size = ui.size;
+       mtd->eb_size = ui.erasesize;
+       mtd->min_io_size = ui.writesize;
+
+       if (mtd->min_io_size <= 0) {
+               errmsg("mtd%d (%s) has insane min. I/O unit size %d",
+                      mtd->dev_num, node, mtd->min_io_size);
+               goto out_close;
+       }
+       if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
+               errmsg("mtd%d (%s) has insane eraseblock size %d",
+                      mtd->dev_num, node, mtd->eb_size);
+               goto out_close;
+       }
+       if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
+               errmsg("mtd%d (%s) has insane size %lld",
+                      mtd->dev_num, node, mtd->size);
+               goto out_close;
+       }
+       mtd->eb_cnt = mtd->size / mtd->eb_size;
+
+       switch(mtd->type) {
+       case MTD_ABSENT:
+               errmsg("mtd%d (%s) is removable and is not present",
+                      mtd->dev_num, node);
+               goto out_close;
+       case MTD_RAM:
+               strcpy((char *)mtd->type_str, "ram");
+               break;
+       case MTD_ROM:
+               strcpy((char *)mtd->type_str, "rom");
+               break;
+       case MTD_NORFLASH:
+               strcpy((char *)mtd->type_str, "nor");
+               break;
+       case MTD_NANDFLASH:
+               strcpy((char *)mtd->type_str, "nand");
+               break;
+       case MTD_DATAFLASH:
+               strcpy((char *)mtd->type_str, "dataflash");
+               break;
+       case MTD_UBIVOLUME:
+               strcpy((char *)mtd->type_str, "ubi");
+               break;
+       default:
+               goto out_close;
+       }
+
+       if (ui.flags & MTD_WRITEABLE)
+               mtd->writable = 1;
+       mtd->subpage_size = mtd->min_io_size;
+
+       close(fd);
+
+       /*
+        * Unfortunately, the device name is not available via ioctl, and
+        * we have to parse /proc/mtd to get it.
+        */
+       ret = proc_parse_start(&pi);
+       if (ret)
+               return -1;
+
+       while (proc_parse_next(&pi)) {
+               if (pi.dev_num == mtd->dev_num) {
+                       strcpy((char *)mtd->name, pi.name);
+                       return 0;
+               }
+       }
+
+       errmsg("mtd%d not found in \"%s\"", mtd->dev_num, MTD_PROC_FILE);
+       errno = ENOENT;
+       return -1;
+
+out_close:
+       close(fd);
+       return -1;
+}
+
+/**
+ * legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'.
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_dev_info1()' and has the same
+ * conventions.
+ */
+int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd)
+{
+       char node[sizeof(MTD_DEV_PATT) + 20];
+
+       sprintf(node, MTD_DEV_PATT, dev_num);
+       return legacy_get_dev_info(node, mtd);
+}
index 5c8ce9e6002191d5868ea62c1a70e89b53432263..5b22e215216a5fce02440430e9f8e641bf26f985 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
 #include <dirent.h>
 #include <unistd.h>
-#include <sys/ioctl.h>
 #include <limits.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <libubi.h>
 #include "libubi_int.h"
 #include "common.h"
@@ -94,7 +94,6 @@ static int read_positive_ll(const char *file, long long *value)
        }
 
        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;
@@ -227,7 +226,7 @@ static int read_major(const char *file, int *major, int *minor)
 /**
  * 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
+ * @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.
@@ -422,9 +421,9 @@ static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num,
  * dev_node2num - find UBI device number by its character device node.
  * @lib: UBI library descriptor
  * @node: UBI character device node name
+ * @dev_num: UBI device number is returned here
  *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
+ * This function returns %0 in case of success and %-1 in case of failure.
  */
 static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
 {
@@ -433,8 +432,7 @@ static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
        int i, major, minor;
 
        if (stat(node, &st))
-               return sys_errmsg("cannot get information about \"%s\"",
-                                 node);
+               return sys_errmsg("cannot get information about \"%s\"", node);
 
        if (!S_ISCHR(st.st_mode)) {
                errno = EINVAL;
@@ -749,8 +747,7 @@ int ubi_probe_node(libubi_t desc, const char *node)
        char file[strlen(lib->ubi_vol) + 100];
 
        if (stat(node, &st))
-               return sys_errmsg("cannot get information about \"%s\"",
-                                 node);
+               return sys_errmsg("cannot get information about \"%s\"", node);
 
        if (!S_ISCHR(st.st_mode)) {
                errmsg("\"%s\" is not a character device", node);
@@ -837,9 +834,10 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
                if (!dirent)
                        break;
 
-               if (strlen(dirent->d_name) > 256) {
+               if (strlen(dirent->d_name) >= 255) {
                        errmsg("invalid entry in %s: \"%s\"",
                               lib->sysfs_ubi, dirent->d_name);
+                       errno = EINVAL;
                        goto out_close;
                }
 
@@ -896,6 +894,7 @@ int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
        strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1);
        r.name_len = n;
 
+       desc = desc;
        fd = open(node, O_RDONLY);
        if (fd == -1)
                return sys_errmsg("cannot open \"%s\"", node);
@@ -1036,10 +1035,8 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
        memset(info, '\0', sizeof(struct ubi_dev_info));
        info->dev_num = dev_num;
 
-       if (!dev_present(lib, dev_num)) {
-               errno = ENODEV;
+       if (!dev_present(lib, dev_num))
                return -1;
-       }
 
        sysfs_ubi = opendir(lib->sysfs_ubi);
        if (!sysfs_ubi)
@@ -1056,7 +1053,7 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
                if (!dirent)
                        break;
 
-               if (strlen(dirent->d_name) > 256) {
+               if (strlen(dirent->d_name) >= 255) {
                        errmsg("invalid entry in %s: \"%s\"",
                               lib->sysfs_ubi, dirent->d_name);
                        goto out_close;
@@ -1120,7 +1117,8 @@ int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
 
        err = ubi_probe_node(desc, node);
        if (err != 1) {
-               errno = ENODEV;
+               if (err == 2)
+                       errno = ENODEV;
                return -1;
        }
 
@@ -1196,7 +1194,8 @@ int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
 
        err = ubi_probe_node(desc, node);
        if (err != 2) {
-               errno = ENODEV;
+               if (err == 1)
+                       errno = ENODEV;
                return -1;
        }
 
diff --git a/ubi-utils/src/mtdinfo.c b/ubi-utils/src/mtdinfo.c
new file mode 100644 (file)
index 0000000..849d165
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to get MTD information.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mtd/mtd-user.h>
+
+#include <libubigen.h>
+#include <libmtd.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME    "mtdinfo"
+
+/* The variables below are set by command line arguments */
+struct args {
+       int mtdn;
+       unsigned int all:1;
+       unsigned int ubinfo:1;
+       const char *node;
+};
+
+static struct args args = {
+       .mtdn = -1,
+       .ubinfo = 0,
+       .all = 0,
+       .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+                        " - a tool to print MTD information.";
+
+static const char *optionsstr =
+"-m, --mtdn=<MTD device number>  MTD device number to get information about\n"
+"-u, --ubi-info                  print what would UBI layout be if it was put\n"
+"                                on this MTD device\n"
+"-a, --all                       print information about all MTD devices\n"
+"-h, --help                      print help message\n"
+"-V, --version                   print program version";
+
+static const char *usage =
+"Usage 1: " PROGRAM_NAME " [-m <MTD device number>] [-u] [-h] [-V] [--mtdn <MTD device number>]\n"
+"\t\t[--ubi-info] [--help] [--version]\n"
+"Usage 2: " PROGRAM_NAME " <MTD device node file name> [-u] [-h] [-V] [--ubi-info] [--help]\n"
+"\t\t[--version]\n"
+"Example 1: " PROGRAM_NAME " - (no arguments) print general MTD information\n"
+"Example 2: " PROGRAM_NAME " -m 1 - print information about MTD device number 1\n"
+"Example 3: " PROGRAM_NAME " /dev/mtd0 - print information MTD device /dev/mtd0\n"
+"Example 4: " PROGRAM_NAME " /dev/mtd0 -u - print information MTD device /dev/mtd0\n"
+"\t\t\t\tand include UBI layout information\n"
+"Example 5: " PROGRAM_NAME " -a - print information about all MTD devices\n"
+"\t\t\tand include UBI layout information\n";
+
+static const struct option long_options[] = {
+       { .name = "mtdn",      .has_arg = 1, .flag = NULL, .val = 'm' },
+       { .name = "ubi-info",  .has_arg = 0, .flag = NULL, .val = 'u' },
+       { .name = "all",       .has_arg = 0, .flag = NULL, .val = 'a' },
+       { .name = "help",      .has_arg = 0, .flag = NULL, .val = 'h' },
+       { .name = "version",   .has_arg = 0, .flag = NULL, .val = 'V' },
+       { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+       while (1) {
+               int key;
+               char *endp;
+
+               key = getopt_long(argc, argv, "am:uhV", long_options, NULL);
+               if (key == -1)
+                       break;
+
+               switch (key) {
+               case 'a':
+                       args.all = 1;
+                       break;
+
+               case 'u':
+                       args.ubinfo = 1;
+                       break;
+
+               case 'm':
+                       args.mtdn = strtoul(optarg, &endp, 0);
+                       if (*endp != '\0' || endp == optarg || args.mtdn < 0)
+                               return errmsg("bad MTD device number: \"%s\"", optarg);
+
+                       break;
+
+               case 'h':
+                       fprintf(stderr, "%s\n\n", doc);
+                       fprintf(stderr, "%s\n\n", usage);
+                       fprintf(stderr, "%s\n", optionsstr);
+                       exit(EXIT_SUCCESS);
+
+               case 'V':
+                       fprintf(stderr, "%s\n", PROGRAM_VERSION);
+                       exit(EXIT_SUCCESS);
+
+               case ':':
+                       return errmsg("parameter is missing");
+
+               default:
+                       fprintf(stderr, "Use -h for help\n");
+                       return -1;
+               }
+       }
+
+       if (optind == argc - 1)
+               args.node = argv[optind];
+       else if (optind < argc)
+               return errmsg("more then one MTD device specified (use -h for help)");
+
+       if (args.all && (args.node || args.mtdn != -1)) {
+               args.mtdn = -1;
+               args.node = NULL;
+       }
+
+       return 0;
+}
+
+static int translate_dev(libmtd_t libmtd, const char *node)
+{
+       int err;
+       struct mtd_dev_info mtd;
+
+       err = mtd_get_dev_info(libmtd, node, &mtd);
+       if (err) {
+               if (errno == ENODEV)
+                       return errmsg("\"%s\" does not correspond to any "
+                                     "existing MTD device", node);
+               return sys_errmsg("cannot get information about MTD "
+                                 "device \"%s\"", node);
+       }
+
+       args.mtdn = mtd.dev_num;
+       return 0;
+}
+
+static int print_dev_info(libmtd_t libmtd, const struct mtd_info *mtd_info, int mtdn)
+{
+       int err;
+       struct mtd_dev_info mtd;
+       struct ubigen_info ui;
+
+       err = mtd_get_dev_info1(libmtd, mtdn, &mtd);
+       if (err) {
+               if (errno == ENODEV)
+                       return errmsg("mtd%d does not correspond to any "
+                                     "existing MTD device", mtdn);
+               return sys_errmsg("cannot get information about MTD device %d",
+                                 mtdn);
+       }
+
+       printf("mtd%d\n", mtd.dev_num);
+       printf("Name:                           %s\n", mtd.name);
+       printf("Type:                           %s\n", mtd.type_str);
+       printf("Eraseblock size:                ");
+       ubiutils_print_bytes(mtd.eb_size, 0);
+       printf("\n");
+       printf("Amount of eraseblocks:          %d (", mtd.eb_cnt);
+       ubiutils_print_bytes(mtd.size, 0);
+       printf(")\n");
+       printf("Minimum input/output unit size: %d %s\n",
+              mtd.min_io_size, mtd.min_io_size > 1 ? "bytes" : "byte");
+       if (mtd_info->sysfs_supported)
+               printf("Sub-page size:                  %d %s\n",
+                      mtd.subpage_size,
+                      mtd.subpage_size > 1 ? "bytes" : "byte");
+       else if (mtd.type == MTD_NANDFLASH)
+               printf("Sub-page size:                  unknown\n");
+
+       if (mtd.oob_size > 0)
+               printf("OOB size:                       %d bytes\n",
+                      mtd.oob_size);
+       if (mtd.region_cnt > 0)
+               printf("Additional erase regions:       %d\n", mtd.oob_size);
+       if (mtd_info->sysfs_supported)
+               printf("Character device major/minor:   %d:%d\n",
+                      mtd.major, mtd.minor);
+       printf("Bad blocks are allowed:         %s\n",
+              mtd.bb_allowed ? "true" : "false");
+       printf("Device is writable:             %s\n",
+             mtd.writable ? "true" : "false");
+
+       if (!args.ubinfo)
+               goto out;
+
+       if (!mtd_info->sysfs_supported) {
+               errmsg("cannot provide UBI info, becasue sub-page size is "
+                      "not known");
+               goto out;
+       }
+
+       ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, mtd.subpage_size,
+                        0, 1);
+       printf("Default UBI VID header offset:  %d\n", ui.vid_hdr_offs);
+       printf("Default UBI data offset:        %d\n", ui.data_offs);
+       printf("Default UBI LEB size:           ");
+       ubiutils_print_bytes(ui.leb_size, 0);
+       printf("\n");
+       printf("Maximum UBI volumes count:      %d\n", ui.max_volumes);
+
+out:
+       printf("\n");
+       return 0;
+}
+
+static int print_general_info(libmtd_t libmtd, const struct mtd_info *mtd_info,
+                             int all)
+{
+       int i, err, first = 1;
+       struct mtd_dev_info mtd;
+
+       printf("Count of MTD devices:           %d\n", mtd_info->dev_count);
+       if (mtd_info->dev_count == 0)
+               return 0;
+
+       printf("Present MTD devices:            ");
+       for (i = mtd_info->lowest_dev_num;
+            i <= mtd_info->highest_dev_num; i++) {
+               err = mtd_get_dev_info1(libmtd, i, &mtd);
+               if (err == -1) {
+                       if (errno == ENODEV)
+                               continue;
+
+                       printf("\n");
+                       return sys_errmsg("libmtd failed get MTD device %d "
+                                          "information", i);
+               }
+
+               if (!first)
+                       printf(", mtd%d", i);
+               else {
+                       printf("mtd%d", i);
+                       first = 0;
+               }
+       }
+       printf("\n");
+       printf("Sysfs interface supported:      %s\n",
+              mtd_info->sysfs_supported ? "yes" : "no");
+
+       if (!all)
+               return 0;
+
+       first = 1;
+       printf("\n");
+
+       for (i = mtd_info->lowest_dev_num;
+            i <= mtd_info->highest_dev_num; i++) {
+               err = print_dev_info(libmtd, mtd_info, i);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+       int err;
+       libmtd_t libmtd;
+       struct mtd_info mtd_info;
+
+       err = parse_opt(argc, argv);
+       if (err)
+               return -1;
+
+       libmtd = libmtd_open();
+       if (libmtd == NULL) {
+               if (errno == 0)
+                       return errmsg("MTD is not present in the system");
+               return sys_errmsg("cannot open libmtd");
+       }
+
+       err = mtd_get_info(libmtd, &mtd_info);
+       if (err) {
+               if (errno == ENODEV)
+                       return errmsg("MTD is not present");
+               return sys_errmsg("cannot get MTD information");
+       }
+
+       if (args.node) {
+               /*
+                * A character device was specified, translate this to MTD
+                * device number.
+                */
+               err = translate_dev(libmtd, args.node);
+               if (err)
+                       goto out_libmtd;
+       }
+
+       if (args.mtdn == -1)
+               err = print_general_info(libmtd, &mtd_info, args.all);
+       else
+               err = print_dev_info(libmtd, &mtd_info, args.mtdn);
+       if (err)
+               goto out_libmtd;
+
+       libmtd_close(libmtd);
+       return 0;
+
+out_libmtd:
+       libmtd_close(libmtd);
+       return -1;
+}
index 1c201a62e70f16e32de83e5e962343d113a4af82..b9d3f79a5534ead3cf2d424d058fca076f8fd060 100644 (file)
@@ -45,7 +45,7 @@
 #include "crc32.h"
 #include "common.h"
 
-#define PROGRAM_VERSION "1.2"
+#define PROGRAM_VERSION "1.3"
 #define PROGRAM_NAME    "ubiformat"
 
 /* The variables below are set by command line arguments */
@@ -55,6 +55,7 @@ struct args {
        unsigned int verbose:1;
        unsigned int override_ec:1;
        unsigned int novtbl:1;
+       unsigned int manual_subpage;
        int subpage_size;
        int vid_hdr_offs;
        int ubi_ver;
@@ -633,9 +634,9 @@ static int format(const struct mtd_dev_info *mtd, const struct ubigen_info *ui,
                                   write_size, eb);
 
                        if (errno != EIO) {
-                               if (args.subpage_size != mtd->min_io_size)
-                                       normsg("may be %d is incorrect?",
-                                                       args.subpage_size);
+                               if (!args.subpage_size != mtd->min_io_size)
+                                       normsg("may be sub-page size is "
+                                              "incorrect?");
                                goto out_free;
                        }
 
@@ -682,59 +683,91 @@ out_free:
 int main(int argc, char * const argv[])
 {
        int err, verbose;
+       libmtd_t libmtd;
+       struct mtd_info mtd_info;
        struct mtd_dev_info mtd;
        libubi_t libubi;
        struct ubigen_info ui;
        struct ubi_scan_info *si;
 
+       libmtd = libmtd_open();
+       if (!libmtd)
+               return errmsg("MTD subsystem is not present");
+
        err = parse_opt(argc, argv);
        if (err)
-               return -1;
+               goto out_close_mtd;
 
-       err = mtd_get_dev_info(args.node, &mtd);
-       if (err)
-               return errmsg("cannot get information about \"%s\"", args.node);
+       err = mtd_get_info(libmtd, &mtd_info);
+       if (err) {
+               if (errno == ENODEV)
+                       errmsg("MTD is not present");
+               sys_errmsg("cannot get MTD information");
+               goto out_close_mtd;
+       }
 
-       args.node_fd = open(args.node, O_RDWR);
-       if (args.node_fd == -1)
-               return sys_errmsg("cannot open \"%s\"", args.node);
+       err = mtd_get_dev_info(libmtd, args.node, &mtd);
+       if (err) {
+               sys_errmsg("cannot get information about \"%s\"", args.node);
+               goto out_close_mtd;
+       }
+
+       if (!mtd_info.sysfs_supported) {
+               /*
+                * Linux kernels older than 2.6.30 did not support sysfs
+                * interface, and it is impossible to find out sub-page
+                * size in these kernels. This is why users should
+                * provide -s option.
+                */
+               if (args.subpage_size == 0) {
+                       warnmsg("your MTD system is old and it is impossible "
+                               "to detect sub-page size. Use -s to get rid "
+                               "of this warning");
+                       normsg("assume sub-page to be %d", mtd.subpage_size);
+               } else {
+                       mtd.subpage_size = args.subpage_size;
+                       args.manual_subpage = 1;
+               }
+       } else if (args.subpage_size && args.subpage_size != mtd.subpage_size) {
+               mtd.subpage_size = args.subpage_size;
+               args.manual_subpage = 1;
+       }
 
-       if (args.subpage_size == 0)
-               args.subpage_size = mtd.min_io_size;
-       else {
+       if (args.manual_subpage) {
+               /* Do some sanity check */
                if (args.subpage_size > mtd.min_io_size) {
                        errmsg("sub-page cannot be larger than min. I/O unit");
-                       goto out;
+                       goto out_close;
                }
 
                if (mtd.min_io_size % args.subpage_size) {
-                       errmsg("min. I/O unit size should be multiple of sub-page size");
-                       goto out;
+                       errmsg("min. I/O unit size should be multiple of "
+                              "sub-page size");
+                       goto out_close;
                }
        }
 
+       args.node_fd = open(args.node, O_RDWR);
+       if (args.node_fd == -1) {
+               sys_errmsg("cannot open \"%s\"", args.node);
+               goto out_close_mtd;
+       }
+
        /* Validate VID header offset if it was specified */
        if (args.vid_hdr_offs != 0) {
                if (args.vid_hdr_offs % 8) {
                        errmsg("VID header offset has to be multiple of min. I/O unit size");
-                       goto out;
+                       goto out_close;
                }
                if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd.eb_size) {
                        errmsg("bad VID header offset");
-                       goto out;
+                       goto out_close;
                }
        }
 
-       /*
-        * Because of MTD interface limitations 'mtd_get_dev_info()' cannot get
-        * sub-page so we force the user to pass it via the command line. Let's
-        * hope the user passed us something sane.
-        */
-       mtd.subpage_size = args.subpage_size;
-
        if (!mtd.writable) {
                errmsg("mtd%d (%s) is a read-only device", mtd.dev_num, args.node);
-               goto out;
+               goto out_close;
        }
 
        /* Make sure this MTD device is not attached to UBI */
@@ -747,14 +780,14 @@ int main(int argc, char * const argv[])
                if (!err) {
                        errmsg("please, first detach mtd%d (%s) from ubi%d",
                               mtd.dev_num, args.node, ubi_dev_num);
-                       goto out;
+                       goto out_close;
                }
        }
 
        if (!args.quiet) {
                normsg_cont("mtd%d (%s), size ", mtd.dev_num, mtd.type_str);
                ubiutils_print_bytes(mtd.size, 1);
-               printf(", %d eraseblocks of ", mtd.eb_size);
+               printf(", %d eraseblocks of ", mtd.eb_cnt);
                ubiutils_print_bytes(mtd.eb_size, 1);
                printf(", min. I/O size %d bytes\n", mtd.min_io_size);
        }
@@ -768,7 +801,7 @@ int main(int argc, char * const argv[])
        err = ubi_scan(&mtd, args.node_fd, &si, verbose);
        if (err) {
                errmsg("failed to scan mtd%d (%s)", mtd.dev_num, args.node);
-               goto out;
+               goto out_close;
        }
 
        if (si->good_cnt == 0) {
@@ -777,7 +810,8 @@ int main(int argc, char * const argv[])
        }
 
        if (si->good_cnt < 2 && (!args.novtbl || args.image)) {
-               errmsg("too few non-bad eraseblocks (%d) on mtd%d", si->good_cnt, mtd.dev_num);
+               errmsg("too few non-bad eraseblocks (%d) on mtd%d",
+                      si->good_cnt, mtd.dev_num);
                goto out_free;
        }
 
@@ -842,7 +876,7 @@ int main(int argc, char * const argv[])
        if (!args.quiet && args.override_ec)
                normsg("use erase counter %lld for all eraseblocks", args.ec);
 
-       ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, args.subpage_size,
+       ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, mtd.subpage_size,
                         args.vid_hdr_offs, args.ubi_ver);
 
        if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
@@ -883,11 +917,14 @@ int main(int argc, char * const argv[])
 
        ubi_scan_free(si);
        close(args.node_fd);
+       libmtd_close(libmtd);
        return 0;
 
 out_free:
        ubi_scan_free(si);
-out:
+out_close:
        close(args.node_fd);
+out_close_mtd:
+       libmtd_close(libmtd);
        return -1;
 }
index 036ed6c20fc5c4215c77a46c0f39b8d8c4c21ff8..8c5a1a9a562f9c01218fb568eeeabaa5b1a80d00 100644 (file)
@@ -30,7 +30,7 @@
 #include <libubi.h>
 #include "common.h"
 
-#define PROGRAM_VERSION "1.0"
+#define PROGRAM_VERSION "1.1"
 #define PROGRAM_NAME    "ubinfo"
 
 /* The variables below are set by command line arguments */
@@ -131,7 +131,7 @@ static int parse_opt(int argc, char * const argv[])
        if (optind == argc - 1)
                args.node = argv[optind];
        else if (optind < argc)
-               return errmsg("more then one UBI devices specified (use -h for help)");
+               return errmsg("more then one UBI device specified (use -h for help)");
 
        return 0;
 }
@@ -216,9 +216,11 @@ static int print_dev_info(libubi_t libubi, int dev_num, int all)
        if (err)
                return sys_errmsg("cannot get information about UBI device %d", dev_num);
 
-       printf("ubi%d:\n", dev_info.dev_num);
+       printf("ubi%d\n", dev_info.dev_num);
        printf("Volumes count:                           %d\n", dev_info.vol_count);
-       printf("Logical eraseblock size:                 %d\n", dev_info.leb_size);
+       printf("Logical eraseblock size:                 ");
+       ubiutils_print_bytes(dev_info.leb_size, 0);
+       printf("\n");
 
        printf("Total amount of logical eraseblocks:     %d (", dev_info.total_lebs);
        ubiutils_print_bytes(dev_info.total_bytes, 0);
@@ -232,7 +234,8 @@ static int print_dev_info(libubi_t libubi, int dev_num, int all)
        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("Minimum input/output unit size:          %d %s\n",
+              dev_info.min_io_size, dev_info.min_io_size > 1 ? "bytes" : "byte");
        printf("Character device major/minor:            %d:%d\n",
               dev_info.major, dev_info.minor);
 
@@ -317,6 +320,7 @@ static int print_general_info(libubi_t libubi, int all)
                        if (errno == ENOENT)
                                continue;
 
+                       printf("\n");
                        return sys_errmsg("libubi failed to probe UBI device %d", i);
                }
 
@@ -339,15 +343,7 @@ static int print_general_info(libubi_t libubi, int all)
             i <= ubi_info.highest_dev_num; i++) {
                if(!first)
                        printf("\n===================================\n\n");
-               err = ubi_get_dev_info1(libubi, i, &dev_info);
-               if (err == -1) {
-                       if (errno == ENOENT)
-                               continue;
-
-                       return sys_errmsg("libubi failed to probe UBI device %d", i);
-               }
                first = 0;
-
                err = print_dev_info(libubi, i, all);
                if (err)
                        return err;