From 747896d1d55f38e23083a3ea2fd6f93fa3259971 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 20 Dec 2007 20:21:02 +0200 Subject: ubi-utils: clean-up and fix ubimkvol Signed-off-by: Artem Bityutskiy --- ubi-utils/Makefile | 2 +- ubi-utils/src/common.c | 52 +++++++ ubi-utils/src/common.h | 34 +++++ ubi-utils/src/ubimkvol.c | 380 ++++++++++++++++++++++++----------------------- 4 files changed, 278 insertions(+), 190 deletions(-) create mode 100644 ubi-utils/src/common.c create mode 100644 ubi-utils/src/common.h diff --git a/ubi-utils/Makefile b/ubi-utils/Makefile index 4d4b827..2baaa07 100644 --- a/ubi-utils/Makefile +++ b/ubi-utils/Makefile @@ -36,7 +36,7 @@ clean: ubiupdatevol: ubiupdatevol.o error.o libubi.o $(CC) $(LDFLAGS) -o $@ $^ -ubimkvol: ubimkvol.o error.o libubi.o +ubimkvol: ubimkvol.o common.o libubi.o $(CC) $(LDFLAGS) -o $@ $^ ubirmvol: ubirmvol.o error.o libubi.o diff --git a/ubi-utils/src/common.c b/ubi-utils/src/common.c new file mode 100644 index 0000000..4a56128 --- /dev/null +++ b/ubi-utils/src/common.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) Artem Bityutskiy, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file contains various common stuff used by UBI utilities. + */ + +#include + +/** + * ubiutils_bytes_multiplier - convert size specifier to an integer + * multiplier. + * + * @str: the size specifier string + * + * This function parses the @str size specifier, which may be one of + * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive + * size multiplier in case of success and %-1 in case of failure. + */ +int ubiutils_get_multiplier(const char *str) +{ + if (!str) + return 1; + + /* Remove spaces before the specifier */ + while (*str == ' ' || *str == '\t') + str += 1; + + if (!strcmp(str, "KiB")) + return 1024; + if (!strcmp(str, "MiB")) + return 1024 * 1024; + if (!strcmp(str, "GiB")) + return 1024 * 1024 * 1024; + + return -1; +} diff --git a/ubi-utils/src/common.h b/ubi-utils/src/common.h new file mode 100644 index 0000000..30daabe --- /dev/null +++ b/ubi-utils/src/common.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) Artem Bityutskiy, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __UBI_UTILS_COMMON_H__ +#define __UBI_UTILS_COMMON_H__ + +/* Error messages */ +#define errmsg(fmt, ...) do { \ + fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \ +} while(0) + +/* Warnings */ +#define warnmsg(fmt, ...) do { \ + fprintf(stderr, "Warning: " fmt "\n", ##__VA_ARGS__); \ +} while(0) + +int ubiutils_get_multiplier(const char *str); + +#endif /* !__UBI_UTILS_COMMON_H__ */ diff --git a/ubi-utils/src/ubimkvol.c b/ubi-utils/src/ubimkvol.c index bff6068..a7066ec 100644 --- a/ubi-utils/src/ubimkvol.c +++ b/ubi-utils/src/ubimkvol.c @@ -29,6 +29,7 @@ * 1.3 Removed argp because we want to use uClibc. * 1.4 Minor cleanups * 1.5 Use a different libubi + * 1.6 Various fixes */ #include @@ -40,8 +41,13 @@ #include #include +#include "common.h" -#define PROGRAM_VERSION "1.5" +#define PROGRAM_VERSION "1.6" +#define PROGRAM_NAME "ubimkvol" + +/* Maximum device node name length */ +#define MAX_NODE_LEN 255 /* * The variables below are set by command line arguments. @@ -54,12 +60,8 @@ struct args { int alignment; char *name; int nlen; - char node[256]; + char node[MAX_NODE_LEN + 1]; int maxavs; - - /* special stuff needed to get additional arguments */ - char *arg1; - char **options; /* [STRING...] */ }; static struct args myargs = { @@ -75,163 +77,144 @@ static struct args myargs = { static int param_sanity_check(struct args *args, libubi_t libubi); -static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" - "ubinkvol - make UBI Volume.\n"; +static char doc[] = "Version " PROGRAM_VERSION "\n" +PROGRAM_NAME " - a tool to create UBI volumes."; static const char *optionsstr = -" -a, --alignment= volume alignment (default is 1)\n" -" -d, --devn= UBI device\n" -" -n, --vol_id= UBI volume id, if not specified, the volume ID\n" -" will be assigned automatically\n" -" -N, --name= volume name\n" -" -s, --size= volume size volume size in bytes, kilobytes (KiB)\n" -" or megabytes (MiB)\n" -" -m, --maxavsize set volume size to maximum available size\n" -" -t, --type= volume type (dynamic, static), default is\n" -" dynamic\n" -" -?, --help Give this help list\n" -" --usage Give a short usage message\n" -" -V, --version Print program version\n"; +"-a, --alignment= volume alignment (default is 1)\n" +"-d, --devn= UBI device number (depricated, do not use)" +"-n, --vol_id= UBI volume ID, if not specified, the volume ID\n" +" will be assigned automatically\n" +"-N, --name= volume name\n" +"-s, --size= volume size volume size in bytes, kilobytes (KiB)\n" +" or megabytes (MiB)\n" +"-m, --maxavsize set volume size to maximum available size\n" +"-t, --type= volume type (dynamic, static), default is dynamic\n" +"-h, --help help message\n" +"-V, --version print program version"; static const char *usage = -"Usage: ubimkvol [-?V] [-a ] [-d ] [-n ]\n" -" [-N ] [-s ] [-t ] [-m]\n" -" [--alignment=] [--devn=] [--vol_id=]\n" -" [--name=] [--size=] [--type=] [--help]\n" -" [--usage] [--version] [--maxavsize]\n"; +"Usage: " PROGRAM_NAME " [-h] [-a ] [-d ] [-n ]\n" +"\t\t\t[-N ] [-s ] [-t ] [-V] [-m]\n" +"\t\t\t[--alignment=] [--devn=] [--vol_id=]\n" +"\t\t\t[--name=] [--size=] [--type=]\n" +"\t\t\t[--help] [--version] [--maxavsize]"; 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' }, - { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' }, - { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, - { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, - { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, + { .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' }, + { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' }, + { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, { .name = "maxavsize", .has_arg = 0, .flag = NULL, .val = 'm' }, { NULL, 0, NULL, 0} }; -/* - * @brief Parse the arguments passed into the test case. - * - * @param argc The number of arguments - * @param argv The list of arguments - * @param args Pointer to argument structure - * - * @return error - * - */ -static int -parse_opt(int argc, char **argv, struct args *args) +static int parse_opt(int argc, char * const argv[], struct args *args) { char *endp; while (1) { int key; - key = getopt_long(argc, argv, "a:d:n:N:s:t:?Vm", long_options, NULL); + key = getopt_long(argc - 1, &argv[1], "a:d:n:N:s:t:hVm", + long_options, NULL); if (key == -1) break; switch (key) { - case 't': - if (!strcmp(optarg, "dynamic")) - args->vol_type = UBI_DYNAMIC_VOLUME; - else if (!strcmp(optarg, "static")) - args->vol_type = UBI_STATIC_VOLUME; - else { - fprintf(stderr, - "Bad volume type: \"%s\"\n", - optarg); - goto out; - } - break; - case 's': - args->bytes = strtoull(optarg, &endp, 0); - if (endp == optarg || args->bytes < 0) { - fprintf(stderr, - "Bad volume size: \"%s\"\n", - optarg); - goto out; - } - if (endp != '\0') { - if (strcmp(endp, "KiB") == 0) - args->bytes *= 1024; - else if (strcmp(endp, "MiB") == 0) - args->bytes *= 1024*1024; - } - break; - case 'a': - args->alignment = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - args->alignment <= 0) { - fprintf(stderr, "Bad volume alignment: " - "\"%s\"\n", optarg); - goto out; - } - break; - case 'd': /* --devn= */ - args->devn = strtoul(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - args->devn < 0) { - fprintf(stderr, - "Bad UBI device number: " - "\"%s\"\n", optarg); - goto out; - } - sprintf(args->node, "/dev/ubi%d", args->devn); - break; - case 'n': /* --volid= */ - args->vol_id = strtoul(optarg, &endp, 0); - if (*endp != '\0' || - endp == optarg || - (args->vol_id < 0 && - args->vol_id != UBI_DYNAMIC_VOLUME)) { - fprintf(stderr, "Bad volume ID: " - "\"%s\"\n", optarg); - goto out; + case 't': + if (!strcmp(optarg, "dynamic")) + args->vol_type = UBI_DYNAMIC_VOLUME; + else if (!strcmp(optarg, "static")) + args->vol_type = UBI_STATIC_VOLUME; + else { + errmsg("bad volume type: \"%s\"", optarg); + return -1; + } + break; + + case 's': + args->bytes = strtoull(optarg, &endp, 0); + if (endp == optarg || args->bytes < 0) { + errmsg("bad volume size: \"%s\"", optarg); + return -1; + } + if (*endp != '\0') { + int mult = ubiutils_get_multiplier(endp); + + if (mult == -1) { + errmsg("bad size specifier: \"%s\" - " + "should be 'KiB', 'MiB' or 'GiB'", endp); + return -1; } - break; - case 'N': - args->name = optarg; - args->nlen = strlen(args->name); - break; - - case ':': - fprintf(stderr, "Parameter is missing\n"); - goto out; - - case '?': /* help */ - fprintf(stderr, - "Usage: ubimkvol [OPTION...]\n"); - fprintf(stderr, "%s", doc); - fprintf(stderr, "%s", optionsstr); - fprintf(stderr, "\nReport bugs to %s\n", - PACKAGE_BUGREPORT); - exit(0); - break; - - case 'V': - fprintf(stderr, "%s\n", PROGRAM_VERSION); - exit(0); - break; - - case 'm': - args->maxavs = 1; - break; - - default: - fprintf(stderr, "%s", usage); - exit(-1); + args->bytes *= mult; + } + break; + + case 'a': + args->alignment = strtoul(optarg, &endp, 0); + if (*endp != '\0' || endp == optarg || args->alignment <= 0) { + errmsg("bad volume alignment: \"%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; + } + + warnmsg("-d and --devn options are depricated and will be removed" + "soon, pass 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) { + errmsg("bad volume ID: " "\"%s\"", optarg); + return -1; + } + break; + + case 'N': + args->name = optarg; + args->nlen = strlen(args->name); + break; + + case 'h': + fprintf(stderr, "%s\n\n", doc); + fprintf(stderr, "%s\n\n", usage); + fprintf(stderr, "%s\n", optionsstr); + exit(0); + + case ':': + errmsg("parameter is missing"); + return -1; + + case 'V': + fprintf(stderr, "%s\n", PROGRAM_VERSION); + exit(0); + + case 'm': + args->maxavs = 1; + break; + + default: + fprintf(stderr, "Use -h for help"); + exit(-1); } } return 0; - out: - return -1; } static int param_sanity_check(struct args *args, libubi_t libubi) @@ -240,111 +223,130 @@ static int param_sanity_check(struct args *args, libubi_t libubi) struct ubi_info ubi; if (args->bytes == 0 && !args->maxavs) { - fprintf(stderr, "Volume size was not specified\n"); - goto out; + errmsg("volume size was not specified (use -h for help)"); + return -1; } if (args->name == NULL) { - fprintf(stderr, "Volume name was not specified\n"); - goto out; + errmsg("volume name was not specified (use -h for help)"); + return -1; } err = ubi_get_info(libubi, &ubi); - if (err) + if (err) { + errmsg("cannot get UBI information"); + perror("ubi_get_info"); return -1; + } if (args->devn >= (int)ubi.dev_count) { - fprintf(stderr, "Device %d does not exist\n", args->devn); - goto out; + errmsg("UBI device %d does not exist", args->devn); + return -1; } len = strlen(args->name); if (len > UBI_MAX_VOLUME_NAME) { - fprintf(stderr, "Too long name (%d symbols), max is %d\n", + errmsg("too long name (%d symbols), max is %d", len, UBI_MAX_VOLUME_NAME); - goto out; + return -1; } return 0; -out: - errno = EINVAL; - return -1; } int main(int argc, char * const argv[]) { int err; libubi_t libubi; + struct ubi_dev_info dev_info; + struct ubi_vol_info vol_info; struct ubi_mkvol_request req; - err = parse_opt(argc, (char **)argv, &myargs); - if (err) { - fprintf(stderr, "Wrong options ...\n"); - return err == 1 ? 0 : -1; + if (argc < 2) { + errmsg("UBI device name was not specified (use -h for help)"); + return -1; } - if (myargs.devn == -1) { - fprintf(stderr, "Device number was not specified\n"); - fprintf(stderr, "Use -h option for help\n"); + if (argc < 3) { + errmsg("too few arguments (use -h for help)"); return -1; } + if (strlen(argv[1]) > MAX_NODE_LEN) { + errmsg("too long device node name: \"%s\" (%d characters), max. is %d", + argv[1], strlen(argv[1]), MAX_NODE_LEN); + return -1; + } + + strcpy(myargs.node, argv[1]); + + err = parse_opt(argc, (char **)argv, &myargs); + if (err) + return err; + libubi = libubi_open(); if (libubi == NULL) { - perror("Cannot open libubi"); + errmsg("cannot open libubi"); + perror("libubi_open"); return -1; } err = param_sanity_check(&myargs, libubi); + if (err) + goto out_libubi; + + err = ubi_get_dev_info(libubi, myargs.node, &dev_info); if (err) { - perror("Input parameters check"); - fprintf(stderr, "Use -h option for help\n"); + errmsg("cannot get information about UBI device number %d (%s)", + myargs.devn, myargs.node); + perror("ubi_get_dev_info"); goto out_libubi; } - req.vol_id = myargs.vol_id; - req.alignment = myargs.alignment; - if (myargs.maxavs) { - struct ubi_dev_info ubi_dev; - - err = ubi_get_dev_info1(libubi, myargs.devn, &ubi_dev); - if (err) { - perror("Can't get UBI device info"); - goto out_libubi; - } - req.bytes = ubi_dev.avail_bytes; - if (!req.bytes) { - fprintf(stderr, "There is no available free space on device!\n"); - goto out_libubi; - } - printf("Setting the volume size to %lld\n", req.bytes); - } else - req.bytes = myargs.bytes; + myargs.bytes = dev_info.avail_bytes; + printf("Set volume size to %lld\n", req.bytes); + } + req.vol_id = myargs.vol_id; + req.alignment = myargs.alignment; + req.bytes = myargs.bytes; req.vol_type = myargs.vol_type; req.name = myargs.name; err = ubi_mkvol(libubi, myargs.node, &req); if (err < 0) { - perror("Cannot create volume"); - fprintf(stderr, " err=%d\n", err); + errmsg("cannot UBI create volume"); + perror("ubi_mkvol"); goto out_libubi; } - /* - * This is hacky, but we want to wait until udev has created device - * nodes. There is probably better way do do this, though. - */ - if (system("udevsettle")) { - /* Well, this is to keep GCC silent */ + myargs.vol_id = req.vol_id; + + /* Print information about the created device */ + err = ubi_get_vol_info1(libubi, dev_info.dev_num, myargs.vol_id, &vol_info); + if (err) { + errmsg("cannot get information about newly created UBI volume"); + perror("ubi_get_vol_info1"); + goto out_libubi; } - /* printf("Created volume %d, %lld bytes, type %s, name %s\n", - vol_id, bytes, vol_type == UBI_DYNAMIC_VOLUME ? - "dynamic" : "static", name); */ + 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\"\n", + vol_info.eb_size, ((double) vol_info.eb_size) / 1024, + req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static", + vol_info.name); - myargs.vol_id = err; libubi_close(libubi); return 0; -- cgit v1.2.3