[PATCH] ubiblock: Support UBI volume name or volume ID parameter passing

Ezequiel Garcia ezequiel.garcia at free-electrons.com
Thu Apr 10 07:43:40 PDT 2014


In addition to the previous bevahior, this commit adds support for
ubiblock to identify a UBI volume based on the volume name or ID.

For example, the following command invocations are possible:

  $ ubiblock --create=/dev/ubi0_0   - create from UBI volume node
  $ ubiblock -r /dev/ubi0_0         - remove from UBI volume node

  $ ubiblock -c /dev/ubi0 -n 99     - create from UBI volume 99 from UBI device
  $ ubiblock -r /dev/ubi0 -N my_vol - remove from UBI volume named "my_vol" from UBI device

The implementation assume there's device node file named as "/dev/ubi${%d}_${%d}",
where the first integer is the UBI device number, and the second is the
UBI volume ID. This device is not strictly required to exist for a given volume,
so the implementation is a "best-effort".

For this reason, the open_volume_by_id is implemented here instead of adding
it to libubi.

Signed-off-by: Ezequiel Garcia <ezequiel.garcia at free-electrons.com>
---
 ubi-utils/ubiblock.c | 165 +++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 133 insertions(+), 32 deletions(-)

diff --git a/ubi-utils/ubiblock.c b/ubi-utils/ubiblock.c
index 1e12be8..a599576 100644
--- a/ubi-utils/ubiblock.c
+++ b/ubi-utils/ubiblock.c
@@ -34,49 +34,118 @@
 #include <libubi.h>
 #include "common.h"
 
+enum operation {
+	UBIBLOCK_NONE,
+	UBIBLOCK_CREATE,
+	UBIBLOCK_REMOVE,
+};
+
 struct args {
+	int vol_id;
 	const char *node;
-	int create;
+	const char *name;
+	enum operation op;
 };
 
-static struct args args;
+static struct args args = {
+	.op = UBIBLOCK_NONE,
+	.vol_id = -1,
+};
 
 static const char doc[] = PROGRAM_NAME " version " VERSION
 			 " - a tool to create/remove block device interface from UBI volumes.";
 
 static const char optionsstr[] =
-"-c, --create               create block on top of a volume\n"
-"-r, --remove               remove block from volume\n"
-"-h, --help                 print help message\n"
-"-V, --version              print program version";
+"-c, --create=<UBI device/volume node>	create block on top of a volume\n"
+"-r, --remove=<UBI device/volume node>	remove block from volume\n"
+"-n, --vol_id=<volume id>		volume ID\n"
+"-N, --name=<volume name>		volume name\n"
+"-h, --help				print help message\n"
+"-V, --version				print program version";
 
 static const char usage[] =
-"Usage: " PROGRAM_NAME " [-c,-r] <UBI volume node file name>\n"
-"Example: " PROGRAM_NAME " --create /dev/ubi0_0";
+"Usage: " PROGRAM_NAME " [-c,-r] <UBI device or UBI volume node file name>\n"
+"         [-n <volume id>] [--vol_id=<volume id>]\n"
+"         [-N <volume name>] [--name=<volume name>] [-h] [--help]\n\n"
+"Example: " PROGRAM_NAME " --create=/dev/ubi0_0   - create from UBI volume node\n"
+"         " PROGRAM_NAME " -c /dev/ubi0 -n 1      - create from UBI volume 1 from UBI device\n"
+"         " PROGRAM_NAME " -r /dev/ubi0 -N my_vol - remove from UBI volume named \"my_vol\" from UBI device";
 
 static const struct option long_options[] = {
 	{ .name = "create",   .has_arg = 1, .flag = NULL, .val = 'c' },
 	{ .name = "remove",   .has_arg = 1, .flag = NULL, .val = 'r' },
+	{ .name = "vol_id",   .has_arg = 1, .flag = NULL, .val = 'n' },
+	{ .name = "name",     .has_arg = 1, .flag = NULL, .val = 'N' },
 	{ .name = "help",     .has_arg = 0, .flag = NULL, .val = 'h' },
 	{ .name = "version",  .has_arg = 0, .flag = NULL, .val = 'V' },
 	{ NULL, 0, NULL, 0}
 };
 
-static int parse_opt(int argc, char * const argv[])
+static int param_sanity_check(libubi_t libubi)
+{
+	int err;
+
+	if (args.op == UBIBLOCK_NONE) {
+		errmsg("please, specify a creation or removal operation");
+		return -1;
+	}
+
+	err = ubi_probe_node(libubi, args.node);
+	if (err == 2) {
+		/* UBI volume node, don't need volume ID or name */
+		return 0;
+	} else if (err == 1) {
+		/* UBI device node, we need volume ID or name */
+		;
+	} else if (err < 0) {
+		if (errno == ENODEV)
+			errmsg("\"%s\" is not an UBI device node", args.node);
+		else
+			errmsg("error while probing \"%s\"", args.node);
+		return -1;
+	}
+
+	if (args.vol_id == -1 && !args.name) {
+		errmsg("please, specify either volume ID or volume name");
+		return -1;
+	}
+
+	if (args.vol_id != -1 && args.name) {
+		errmsg("please, specify either volume ID or volume name, not both");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int parse_opt(libubi_t libubi, int argc, char * const argv[])
 {
 	while (1) {
-		int key;
+		int key, error = 0;
 
-		key = getopt_long(argc, argv, "c:r:h?V", long_options, NULL);
+		key = getopt_long(argc, argv, "n:N:c:r:h?V", long_options, NULL);
 		if (key == -1)
 			break;
 
 		switch (key) {
 		case 'c':
-			args.create = 1;
+			args.op = UBIBLOCK_CREATE;
+			args.node = optarg;
+			break;
 		case 'r':
+			args.op = UBIBLOCK_REMOVE;
 			args.node = optarg;
 			break;
+		case 'n':
+			args.vol_id = simple_strtoul(optarg, &error);
+			if (error || args.vol_id < 0) {
+				errmsg("bad volume ID: " "\"%s\"", optarg);
+				return -1;
+			}
+			break;
+		case 'N':
+			args.name = optarg;
+			break;
 		case 'h':
 		case '?':
 			printf("%s\n\n", doc);
@@ -94,20 +163,52 @@ static int parse_opt(int argc, char * const argv[])
 		}
 	}
 
-	if (!args.node)
-		return errmsg("invalid arguments (use -h for help)");
-
+	if (param_sanity_check(libubi))
+		return -1;
 	return 0;
 }
 
-int main(int argc, char * const argv[])
+static int ubi_open_volume_by_id(libubi_t desc, const char *node, int vol_id, int mode)
 {
+	char file[256];
+	struct ubi_dev_info dev_info;
 	int err, fd;
-	libubi_t libubi;
 
-	err = parse_opt(argc, argv);
+	err = ubi_get_dev_info(desc, node, &dev_info);
 	if (err)
+		return errmsg("cannot get information about UBI device \"%s\"", node);
+
+	sprintf(file, "/dev/ubi%d_%d", dev_info.dev_num, vol_id);
+	fd = open(file, mode);
+	if (fd == -1)
+		errmsg("Failed to open '%s' volume device", file);
+	return fd;
+}
+
+static int ubi_open_volume_by_name(libubi_t desc, const char *node, const char *name, int mode)
+{
+	struct ubi_dev_info dev_info;
+	struct ubi_vol_info vol_info;
+	int err;
+
+	err = ubi_get_dev_info(desc, node, &dev_info);
+	if (err) {
+		errmsg("cannot get information about UBI device \"%s\"", node);
+		return -1;
+	}
+
+	err = ubi_get_vol_info1_nm(desc, dev_info.dev_num, name, &vol_info);
+	if (err) {
+		errmsg("cannot find UBI volume \"%s\"", name);
 		return -1;
+	}
+	return ubi_open_volume_by_id(desc, node, vol_info.vol_id, mode);
+}
+
+int main(int argc, char * const argv[])
+{
+	int err, fd;
+	libubi_t libubi;
 
 	libubi = libubi_open();
 	if (!libubi) {
@@ -116,26 +217,26 @@ int main(int argc, char * const argv[])
 		return sys_errmsg("cannot open libubi");
 	}
 
-	err = ubi_probe_node(libubi, args.node);
-	if (err == 1) {
-		errmsg("\"%s\" is an UBI device node, not an UBI volume node",
-		       args.node);
-		goto out_libubi;
-	} else if (err < 0) {
-		if (errno == ENODEV)
-			errmsg("\"%s\" is not an UBI volume node", args.node);
-		else
-			sys_errmsg("error while probing \"%s\"", args.node);
-		goto out_libubi;
+	err = parse_opt(libubi, argc, argv);
+	if (err)
+		return -1;
+
+	if (args.name) {
+		fd = ubi_open_volume_by_name(libubi, args.node, args.name, O_RDWR);
+	} else if (args.vol_id != -1) {
+		fd = ubi_open_volume_by_id(libubi, args.node, args.vol_id, O_RDWR);
+	} else {
+		fd = open(args.node, O_RDWR);
+		if (fd == -1)
+			errmsg("Failed to open '%s' volume device", args.node);
 	}
 
-	fd = open(args.node, O_RDWR);
 	if (fd == -1) {
-		sys_errmsg("cannot open UBI volume \"%s\"", args.node);
+		sys_errmsg("cannot open UBI volume device");
 		goto out_libubi;
 	}
 
-	if (args.create) {
+	if (args.op == UBIBLOCK_CREATE) {
 		err = ubi_vol_block_create(fd);
 		if (err) {
 			if (errno == ENOSYS)
-- 
1.9.1




More information about the linux-mtd mailing list