summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ubi-utils/Makefile7
-rw-r--r--ubi-utils/inc/libubi.h172
-rw-r--r--ubi-utils/src/common.c35
-rw-r--r--ubi-utils/src/common.h17
-rw-r--r--ubi-utils/src/libubi.c1200
-rw-r--r--ubi-utils/src/libubi_int.h86
-rw-r--r--ubi-utils/src/ubimkvol.c88
-rw-r--r--ubi-utils/src/ubinfo.c461
-rw-r--r--ubi-utils/src/ubirmvol.c66
9 files changed, 1362 insertions, 770 deletions
diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile
index 1a3b2b9..ee4956f 100644
--- a/ubi-utils/Makefile
+++ b/ubi-utils/Makefile
@@ -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 $@ $^
diff --git a/ubi-utils/inc/libubi.h b/ubi-utils/inc/libubi.h
index d39c1b9..21be68a 100644
--- a/ubi-utils/inc/libubi.h
+++ b/ubi-utils/inc/libubi.h
@@ -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.
diff --git a/ubi-utils/src/common.c b/ubi-utils/src/common.c
index 4a56128..761d47d 100644
--- a/ubi-utils/src/common.c
+++ b/ubi-utils/src/common.c
@@ -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(")");
+}
diff --git a/ubi-utils/src/common.h b/ubi-utils/src/common.h
index c20d308..0e33dd1 100644
--- a/ubi-utils/src/common.h
+++ b/ubi-utils/src/common.h
@@ -19,19 +19,28 @@
#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__ */
diff --git a/ubi-utils/src/libubi.c b/ubi-utils/src/libubi.c
index 4d2b725..ecc12b4 100644
--- a/ubi-utils/src/libubi.c
+++ b/ubi-utils/src/libubi.c
@@ -34,6 +34,484 @@
#include "libubi.h"
#include "libubi_int.h"
+/**
+ * mkpath - compose full path from 2 given components.
+ * @path: the first component
+ * @name: the second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+ char *n;
+ int len1 = strlen(path);
+ int len2 = strlen(name);
+
+ n = malloc(len1 + len2 + 2);
+ if (!n) {
+ errmsg("cannot allocate %d bytes", len1 + len2 + 2);
+ perror("malloc");
+ return NULL;
+ }
+
+ memcpy(n, path, len1);
+ if (n[len1 - 1] != '/')
+ n[len1++] = '/';
+
+ memcpy(n + len1, name, len2 + 1);
+ return n;
+}
+
+/**
+ * read_positive_ll - read a positive 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as a positive
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_positive_ll(const char *file, long long *value)
+{
+ int fd, rd;
+ char buf[50];
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, 50);
+ if (rd == -1) {
+ 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;
+ }
+
+ if (sscanf(buf, "%lld\n", value) != 1) {
+ /* This must be a UBI bug */
+ errmsg("cannot read integer from \"%s\"\n", file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (*value < 0) {
+ errmsg("negative value %lld in \"%s\"", *value, file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (close(fd)) {
+ errmsg("close failed on \"%s\"", file);
+ perror("close");
+ return -1;
+ }
+
+ return 0;
+
+out_error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * read_positive_int - read a positive 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_positive_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_positive_int(const char *file, int *value)
+{
+ long long res;
+
+ if (read_positive_ll(file, &res))
+ return -1;
+
+ /* Make sure the value is not too big */
+ if (res > INT_MAX) {
+ errmsg("value %lld read from file \"%s\" is out of range",
+ res, file);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *value = res;
+ return 0;
+}
+
+/**
+ * read_data - read data from a file.
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure. Note, if the file contains more then @buf_len bytes of
+ * date, this function fails with %EINVAL error code.
+ */
+static int read_data(const char *file, void *buf, int buf_len)
+{
+ int fd, rd, tmp, tmp1;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, buf_len);
+ if (rd == -1) {
+ errmsg("cannot read \"%s\"", file);
+ perror("read");
+ goto out_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;
+ }
+
+ if (close(fd)) {
+ errmsg("close failed on \"%s\"", file);
+ perror("close");
+ return -1;
+ }
+
+ return rd;
+
+out_error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * read_major - read major and minor numbers from a file.
+ * @file: name of the file to read from
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns % in case of succes, and %-1 in case of failure.
+ */
+static int read_major(const char *file, int *major, int *minor)
+{
+ int ret;
+ char buf[50];
+
+ ret = read_data(file, buf, 50);
+ if (ret < 0)
+ return ret;
+
+ ret = sscanf(buf, "%d:%d\n", major, minor);
+ if (ret != 2) {
+ errmsg("\"%s\" does not have major:minor format", file);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*major < 0 || *minor < 0) {
+ errmsg("bad major:minor %d:%d in \"%s\"",
+ *major, *minor, file);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * dev_read_int - read a positive 'int' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_int(const char *patt, int dev_num, int *value)
+{
+ char file[strlen(patt) + 50];
+
+ sprintf(file, patt, dev_num);
+ return read_positive_int(file, value);
+}
+
+/**
+ * vol_read_int - read a positive 'int' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_positive_int(file, value);
+}
+
+/**
+ * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_ll(const char *patt, int dev_num, long long *value)
+{
+ char file[strlen(patt) + 50];
+
+ sprintf(file, patt, dev_num);
+ return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+ long long *value)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_data - read data from an UBI volume's sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @buf: buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+ int buf_len)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_data(file, buf, buf_len);
+}
+
+/**
+ * dent_is_dir - check if a file is a directory.
+ * @dir: the base directory path of the file
+ * @name: file name
+ *
+ * This function returns %1 if file @name in directory @dir is a directoru, and
+ * %0 if not.
+ */
+static int dent_is_dir(const char *dir, const char *name)
+{
+ int ret;
+ struct stat st;
+ char full_path[strlen(dir) + strlen(name) + 2];
+
+ sprintf(full_path, "%s/%s", dir, name);
+ ret = lstat(full_path, &st);
+ if (ret) {
+ errmsg("lstat failed on \"%s\"", full_path);
+ perror("lstat");
+ return -1;
+ }
+
+ return !!S_ISDIR(st.st_mode);
+}
+
+/**
+ * dev_get_major - get major and minor numbers of an UBI device.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor)
+{
+ char file[strlen(lib->dev_dev) + 50];
+
+ sprintf(file, lib->dev_dev, dev_num);
+ return read_major(file, major, minor);
+}
+
+/**
+ * vol_get_major - get major and minor numbers of an UBI volume.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_get_major(struct libubi *lib, int dev_num, int vol_id,
+ int *major, int *minor)
+{
+ char file[strlen(lib->vol_dev) + 100];
+
+ sprintf(file, lib->vol_dev, dev_num, vol_id);
+ return read_major(file, major, minor);
+}
+
+/**
+ * vol_node2nums - find UBI device number and volume ID by volume device node
+ * file.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ * @dev_num: UBI device number is returned here
+ * @vol_id: volume ID is returned hers
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num,
+ int *vol_id)
+{
+ struct stat st;
+ struct ubi_info info;
+ int i, fd, major, minor;
+ char file[strlen(lib->ubi_vol) + 100];
+
+ if (lstat(node, &st))
+ return -1;
+
+ if (!S_ISCHR(st.st_mode)) {
+ errmsg("\"%s\" is not a character device", node);
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(st.st_rdev);
+ minor = minor(st.st_rdev);
+
+ if (minor == 0) {
+ errmsg("\"%s\" is not a volume character device", node);
+ errno = -EINVAL;
+ return -1;
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major)
+ break;
+ }
+
+ if (i > info.highest_dev_num) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Make sure this UBI volume exists */
+ sprintf(file, lib->ubi_vol, i, minor - 1);
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ *dev_num = i;
+ *vol_id = minor - 1;
+ return 0;
+}
+
+/**
+ * dev_node2num - find UBI device number by its character device node.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ *
+ * This function returns positive UBI device number in case of success and %-1
+ * in case of failure.
+ */
+static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
+{
+ struct stat stat;
+ struct ubi_info info;
+ int i, major, minor;
+
+ if (lstat(node, &stat))
+ return -1;
+
+ if (!S_ISCHR(stat.st_mode)) {
+ errmsg("\"%s\" is not a character device", node);
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(stat.st_rdev);
+ minor = minor(stat.st_rdev);
+
+ if (minor != 0) {
+ errmsg("\"%s\" is not an UBI character device", node);
+ errno = -EINVAL;
+ return -1;
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major) {
+ if (minor1 != 0) {
+ errmsg("UBI character device minor number is "
+ "%d, but must be 0", minor1);
+ errno = EINVAL;
+ return -1;
+ }
+ *dev_num = i;
+ return 0;
+ }
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
libubi_t libubi_open(void)
{
int fd, version;
@@ -46,132 +524,127 @@ libubi_t libubi_open(void)
/* TODO: this must be discovered instead */
lib->sysfs = strdup("/sys");
if (!lib->sysfs)
- goto error;
+ goto out_error;
+
+ lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL);
+ if (!lib->sysfs_ctrl)
+ goto out_error;
+
+ lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV);
+ if (!lib->ctrl_dev)
+ goto out_error;
lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
if (!lib->sysfs_ubi)
- goto error;
+ goto out_error;
/* Make sure UBI is present */
fd = open(lib->sysfs_ubi, O_RDONLY);
- if (fd == -1)
- goto error;
- close(fd);
+ if (fd == -1) {
+ errmsg("cannot open \"%s\", UBI does not seem to exist in system",
+ lib->sysfs_ubi);
+ goto out_error;
+ }
+
+ if (close(fd)) {
+ errmsg("close failed on \"%s\"", lib->sysfs_ubi);
+ perror("close");
+ goto out_error;
+ }
lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
if (!lib->ubi_dev)
- goto error;
+ goto out_error;
lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
if (!lib->ubi_version)
- goto error;
+ goto out_error;
lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
if (!lib->dev_dev)
- goto error;
+ goto out_error;
lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
if (!lib->dev_avail_ebs)
- goto error;
+ goto out_error;
lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
if (!lib->dev_total_ebs)
- goto error;
+ goto out_error;
lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
if (!lib->dev_bad_count)
- goto error;
+ goto out_error;
lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
if (!lib->dev_eb_size)
- goto error;
+ goto out_error;
lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
if (!lib->dev_max_ec)
- goto error;
+ goto out_error;
lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
if (!lib->dev_bad_rsvd)
- goto error;
+ goto out_error;
lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
if (!lib->dev_max_vols)
- goto error;
+ goto out_error;
lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE);
if (!lib->dev_min_io_size)
- goto error;
+ goto out_error;
lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
if (!lib->ubi_vol)
- goto error;
+ goto out_error;
lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
if (!lib->vol_type)
- goto error;
+ goto out_error;
lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
if (!lib->vol_dev)
- goto error;
+ goto out_error;
lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
if (!lib->vol_alignment)
- goto error;
+ goto out_error;
lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
if (!lib->vol_data_bytes)
- goto error;
+ goto out_error;
lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
if (!lib->vol_rsvd_ebs)
- goto error;
+ goto out_error;
lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
if (!lib->vol_eb_size)
- goto error;
+ goto out_error;
lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
if (!lib->vol_corrupted)
- goto error;
+ goto out_error;
lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
if (!lib->vol_name)
- goto error;
+ goto out_error;
- if (read_int(lib->ubi_version, &version))
- goto error;
+ if (read_positive_int(lib->ubi_version, &version))
+ goto out_error;
if (version != LIBUBI_UBI_VERSION) {
fprintf(stderr, "LIBUBI: this library was made for UBI version "
"%d, but UBI version %d is detected\n",
LIBUBI_UBI_VERSION, version);
- goto error;
+ goto out_error;
}
return lib;
-error:
- free(lib->vol_corrupted);
- free(lib->vol_eb_size);
- free(lib->vol_rsvd_ebs);
- free(lib->vol_data_bytes);
- free(lib->vol_alignment);
- free(lib->vol_dev);
- free(lib->vol_type);
- free(lib->ubi_vol);
- free(lib->dev_min_io_size);
- free(lib->dev_max_vols);
- free(lib->dev_bad_rsvd);
- free(lib->dev_max_ec);
- free(lib->dev_eb_size);
- free(lib->dev_bad_count);
- free(lib->dev_total_ebs);
- free(lib->dev_avail_ebs);
- free(lib->dev_dev);
- free(lib->ubi_version);
- free(lib->ubi_dev);
- free(lib->sysfs_ubi);
- free(lib->sysfs);
- free(lib);
+out_error:
+ libubi_close((libubi_t)lib);
return NULL;
}
@@ -200,10 +673,74 @@ void libubi_close(libubi_t desc)
free(lib->ubi_version);
free(lib->ubi_dev);
free(lib->sysfs_ubi);
+ free(lib->ctrl_dev);
+ free(lib->sysfs_ctrl);
free(lib->sysfs);
free(lib);
}
+int ubi_node_type(libubi_t desc, const char *node)
+{
+ struct stat st;
+ struct ubi_info info;
+ int i, fd, major, minor;
+ struct libubi *lib = (struct libubi *)desc;
+ char file[strlen(lib->ubi_vol) + 100];
+
+ if (lstat(node, &st))
+ return -1;
+
+ if (!S_ISCHR(st.st_mode)) {
+ errmsg("\"%s\" is not a character device", node);
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(st.st_rdev);
+ minor = minor(st.st_rdev);
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major)
+ break;
+ }
+
+ if (i > info.highest_dev_num) {
+ /*
+ * The character device node does not correspond to any
+ * existing UBI device or volume, but we do not want to return
+ * any error number in this case, to indicate the fact that it
+ * could be a UBI device/volume, but it doesn't.
+ */
+ errno = 0;
+ return -1;
+ }
+
+ if (minor == 0)
+ return 1;
+
+ /* This is supposdely an UBI volume device node */
+ sprintf(file, lib->ubi_vol, i, minor - 1);
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ errno = 0;
+ return -1;
+ }
+
+ return 2;
+}
+
int ubi_get_info(libubi_t desc, struct ubi_info *info)
{
DIR *sysfs_ubi;
@@ -212,20 +749,33 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
memset(info, '\0', sizeof(struct ubi_info));
+ if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor))
+ return -1;
+
/*
* We have to scan the UBI sysfs directory to identify how many UBI
* devices are present.
*/
sysfs_ubi = opendir(lib->sysfs_ubi);
- if (!sysfs_ubi)
+ if (!sysfs_ubi) {
+ errmsg("cannot open %s", lib->sysfs_ubi);
+ perror("opendir");
return -1;
+ }
info->lowest_dev_num = INT_MAX;
while ((dirent = readdir(sysfs_ubi))) {
- char *name = &dirent->d_name[0];
int dev_num, ret;
- ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num);
+ /*
+ * Make sure this direntry is a directory and not a symlink -
+ * Linux puts symlinks to UBI volumes on this UBI device to the
+ * same sysfs directory.
+ */
+ if (!dent_is_dir(lib->sysfs_ubi, dirent->d_name))
+ continue;
+
+ ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT, &dev_num);
if (ret == 1) {
info->dev_count += 1;
if (dev_num > info->highest_dev_num)
@@ -235,15 +785,27 @@ int ubi_get_info(libubi_t desc, struct ubi_info *info)
}
}
+ if (!dirent && errno) {
+ errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+ perror("readdir");
+ goto out_close;
+ }
+
+ if (closedir(sysfs_ubi)) {
+ errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+ perror("closedir");
+ return -1;
+ }
+
if (info->lowest_dev_num == INT_MAX)
info->lowest_dev_num = 0;
- if (read_int(lib->ubi_version, &info->version))
- goto close;
+ if (read_positive_int(lib->ubi_version, &info->version))
+ return -1;
- return closedir(sysfs_ubi);
+ return 0;
-close:
+out_close:
closedir(sysfs_ubi);
return -1;
}
@@ -254,6 +816,8 @@ int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
struct ubi_mkvol_req r;
size_t n;
+ memset(&r, sizeof(struct ubi_mkvol_req), '\0');
+
desc = desc;
r.vol_id = req->vol_id;
r.alignment = req->alignment;
@@ -272,7 +836,7 @@ int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
return -1;
ret = ioctl(fd, UBI_IOCMKVOL, &r);
- if (!ret)
+ if (ret == 0)
req->vol_id = r.vol_id;
close(fd);
@@ -310,7 +874,7 @@ int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
int fd, ret;
struct ubi_rsvol_req req;
- desc = desc;
+ desc = desc;
fd = open(node, O_RDONLY);
if (fd == -1)
return -1;
@@ -331,18 +895,6 @@ int ubi_update_start(libubi_t desc, int fd, long long bytes)
return 0;
}
-int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
-{
- int dev_num;
- struct libubi *lib = (struct libubi *)desc;
-
- dev_num = find_dev_num(lib, node);
- if (dev_num == -1)
- return -1;
-
- return ubi_get_dev_info1(desc, dev_num, info);
-}
-
int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
{
DIR *sysfs_ubi;
@@ -358,10 +910,9 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
info->lowest_vol_num = INT_MAX;
while ((dirent = readdir(sysfs_ubi))) {
- char *name = &dirent->d_name[0];
int vol_id, ret, devno;
- ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id);
+ 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)
@@ -371,11 +922,24 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
}
}
- closedir(sysfs_ubi);
+ if (!dirent && errno) {
+ errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+ perror("readdir");
+ goto out_close;
+ }
+
+ if (closedir(sysfs_ubi)) {
+ errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+ perror("closedir");
+ return -1;
+ }
if (info->lowest_vol_num == INT_MAX)
info->lowest_vol_num = 0;
+ if (dev_get_major(lib, dev_num, &info->major, &info->minor))
+ return -1;
+
if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs))
return -1;
if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs))
@@ -397,22 +961,21 @@ int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
info->total_bytes = info->total_ebs * info->eb_size;
return 0;
+
+out_close:
+ closedir(sysfs_ubi);
+ return -1;
}
-int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
{
- int vol_id, dev_num;
+ int dev_num;
struct libubi *lib = (struct libubi *)desc;
- dev_num = find_dev_num_vol(lib, node);
- if (dev_num == -1)
+ if (dev_node2num(lib, node, &dev_num))
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);
+ return ubi_get_dev_info1(desc, dev_num, info);
}
int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
@@ -426,16 +989,21 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
info->dev_num = dev_num;
info->vol_id = vol_id;
- ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50);
+ if (dev_get_major(lib, dev_num, &info->dev_major, &info->dev_minor))
+ return -1;
+ if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor))
+ return -1;
+
+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50);
if (ret < 0)
return -1;
- if (strncmp(&buf[0], "static\n", ret) == 0)
+ if (strncmp(buf, "static\n", ret) == 0)
info->type = UBI_STATIC_VOLUME;
- else if (strncmp(&buf[0], "dynamic\n", ret) == 0)
+ else if (strncmp(buf, "dynamic\n", ret) == 0)
info->type = UBI_DYNAMIC_VOLUME;
else {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errmsg("bad value at \"%s\"", buf);
errno = EINVAL;
return -1;
}
@@ -469,459 +1037,13 @@ int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
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;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%d\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * dev_read_int - read an 'int' value from an UBI device's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_int(const char *patt, int dev_num, int *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 50];
-
- sprintf(&file[0], patt, dev_num);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%d\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * dev_read_ll - read a 'long long' value from an UBI device's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_ll(const char *patt, int dev_num, long long *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 50];
-
- sprintf(&file[0], patt, dev_num);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%lld\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * dev_read_data - read data from an UBI device's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @buf buffer to read data to
- * @buf_len buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len)
-{
- int fd, rd;
- char file[strlen(patt) + 50];
-
- sprintf(&file[0], patt, dev_num);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, buf, buf_len);
- if (rd == -1) {
- close(fd);
- return -1;
- }
-
- close(fd);
- return rd;
-}
-
-/**
- * vol_read_int - read an 'int' value from an UBI volume's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @vol_id volume identifier
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 100];
-
- sprintf(&file[0], patt, dev_num, vol_id);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%d\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @vol_id volume identifier
- * @value the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int vol_read_ll(const char *patt, int dev_num, int vol_id,
- long long *value)
-{
- int fd, rd;
- char buf[50];
- char file[strlen(patt) + 100];
-
- sprintf(&file[0], patt, dev_num, vol_id);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, &buf[0], 50);
- if (rd == -1)
- goto error;
-
- if (sscanf(&buf[0], "%lld\n", value) != 1) {
- /* This must be a UBI bug */
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- goto error;
- }
-
- close(fd);
- return 0;
-
-error:
- close(fd);
- return -1;
-}
-
-/**
- * vol_read_data - read data from an UBI volume's sysfs file.
- *
- * @patt the file pattern to read from
- * @dev_num UBI device number
- * @vol_id volume identifier
- * @buf buffer to read to
- * @buf_len buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
- int buf_len)
-{
- int fd, rd;
- char file[strlen(patt) + 100];
-
- sprintf(&file[0], patt, dev_num, vol_id);
- fd = open(&file[0], O_RDONLY);
- if (fd == -1)
- return -1;
-
- rd = read(fd, buf, buf_len);
- if (rd == -1) {
- close(fd);
- return -1;
- }
-
- close(fd);
- return rd;
-}
-
-/**
- * mkpath - compose full path from 2 given components.
- *
- * @path first component
- * @name second component
- *
- * This function returns the resulting path in case of success and %NULL in
- * case of failure.
- */
-static char *mkpath(const char *path, const char *name)
-{
- char *n;
- int len1 = strlen(path);
- int len2 = strlen(name);
-
- n = malloc(len1 + len2 + 2);
- if (!n)
- return NULL;
-
- memcpy(n, path, len1);
- if (n[len1 - 1] != '/')
- n[len1++] = '/';
-
- memcpy(n + len1, name, len2 + 1);
- return n;
-}
-
-/**
- * find_dev_num - find UBI device number by its character device node.
- *
- * @lib UBI library descriptor
- * @node UBI character device node name
- *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
- */
-static int find_dev_num(struct libubi *lib, const char *node)
-{
- struct stat stat;
- struct ubi_info info;
- int i, major, minor;
-
- if (lstat(node, &stat))
- return -1;
-
- if (!S_ISCHR(stat.st_mode)) {
- errno = EINVAL;
- return -1;
- }
-
- major = major(stat.st_rdev);
- minor = minor(stat.st_rdev);
-
- if (minor != 0) {
- errno = -EINVAL;
- return -1;
- }
-
- if (ubi_get_info((libubi_t *)lib, &info))
- return -1;
-
- for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
- int major1, minor1, ret;
- char buf[50];
-
- ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
- if (ret < 0)
- return -1;
-
- ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
- if (ret != 2) {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- return -1;
- }
-
- if (minor1 == minor && major1 == major)
- return i;
- }
-
- errno = ENOENT;
- return -1;
-}
-
-/**
- * find_dev_num_vol - find UBI device number by volume character device node.
- *
- * @lib UBI library descriptor
- * @node UBI character device node name
- *
- * This function returns positive UBI device number in case of success and %-1
- * in case of failure.
- */
-static int find_dev_num_vol(struct libubi *lib, const char *node)
-{
- struct stat stat;
- struct ubi_info info;
- int i, major;
-
- if (lstat(node, &stat))
- return -1;
-
- if (!S_ISCHR(stat.st_mode)) {
- errno = EINVAL;
- return -1;
- }
-
- major = major(stat.st_rdev);
-
- if (minor(stat.st_rdev) == 0) {
- errno = -EINVAL;
- return -1;
- }
-
- if (ubi_get_info((libubi_t *)lib, &info))
- return -1;
-
- for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
- int major1, minor1, ret;
- char buf[50];
-
- ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
- if (ret < 0)
- return -1;
-
- ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
- if (ret != 2) {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- return -1;
- }
-
- if (major1 == major)
- return i;
- }
-
- errno = ENOENT;
- return -1;
-}
-
-/**
- * find_vol_num - find UBI volume number by its character device node.
- *
- * @lib UBI library descriptor
- * @dev_num UBI device number
- * @node UBI volume character device node name
- *
- * This function returns positive UBI volume number in case of success and %-1
- * in case of failure.
- */
-static int find_vol_num(struct libubi *lib, int dev_num, const char *node)
+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
{
- struct stat stat;
- struct ubi_dev_info info;
- int i, major, minor;
-
- if (lstat(node, &stat))
- return -1;
-
- if (!S_ISCHR(stat.st_mode)) {
- errno = EINVAL;
- return -1;
- }
-
- major = major(stat.st_rdev);
- minor = minor(stat.st_rdev);
-
- if (minor == 0) {
- errno = -EINVAL;
- return -1;
- }
+ int vol_id, dev_num;
+ struct libubi *lib = (struct libubi *)desc;
- if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info))
+ if (vol_node2nums(lib, node, &dev_num, &vol_id))
return -1;
- for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) {
- int major1, minor1, ret;
- char buf[50];
-
- ret = vol_read_data(lib->vol_dev, dev_num, i, &buf[0], 50);
- if (ret < 0)
- return -1;
-
- ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
- if (ret != 2) {
- fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
- errno = EINVAL;
- return -1;
- }
-
- if (minor1 == minor && major1 == major)
- return i;
- }
-
- errno = ENOENT;
- return -1;
+ return ubi_get_vol_info1(desc, dev_num, vol_id, info);
}
diff --git a/ubi-utils/src/libubi_int.h b/ubi-utils/src/libubi_int.h
index e68b791..4c26eb5 100644
--- a/ubi-utils/src/libubi_int.h
+++ b/ubi-utils/src/libubi_int.h
@@ -27,16 +27,29 @@
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
diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c
index 454e6fe..488dd17 100644
--- a/ubi-utils/src/ubimkvol.c
+++ b/ubi-utils/src/ubimkvol.c
@@ -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
index 0000000..358f208
--- /dev/null
+++ b/ubi-utils/src/ubinfo.c
@@ -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;
+}
diff --git a/ubi-utils/src/ubirmvol.c b/ubi-utils/src/ubirmvol.c
index b6fb8ef..e9a1b41 100644
--- a/ubi-utils/src/ubirmvol.c
+++ b/ubi-utils/src/ubirmvol.c
@@ -30,7 +30,6 @@
#include <string.h>
#include <errno.h>
-#include <config.h>
#include <libubi.h>
#include "common.h"
@@ -39,18 +38,14 @@
/* 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;