diff options
Diffstat (limited to 'ubi-utils/src/mtdinfo.c')
-rw-r--r-- | ubi-utils/src/mtdinfo.c | 122 |
1 files changed, 119 insertions, 3 deletions
diff --git a/ubi-utils/src/mtdinfo.c b/ubi-utils/src/mtdinfo.c index 38b63ca..b6077e4 100644 --- a/ubi-utils/src/mtdinfo.c +++ b/ubi-utils/src/mtdinfo.c @@ -29,6 +29,7 @@ #include <getopt.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <mtd/mtd-user.h> #include <libubigen.h> @@ -41,6 +42,7 @@ struct args { int mtdn; unsigned int all:1; unsigned int ubinfo:1; + unsigned int map:1; const char *node; }; @@ -59,14 +61,15 @@ static const char optionsstr[] = " (deprecated option, will be removed, do not use)\n" "-u, --ubi-info print what would UBI layout be if it was put\n" " on this MTD device\n" +"-M, --map print eraseblock map\n" "-a, --all print information about all MTD devices\n" "-h, --help print help message\n" "-V, --version print program version"; static const char usage[] = -"Usage 1: " PROGRAM_NAME " [-m <MTD device number>] [-u] [-h] [-V] [--mtdn <MTD device number>]\n" +"Usage 1: " PROGRAM_NAME " [-m <MTD device number>] [-u] [-M] [-h] [-V] [--mtdn <MTD device number>]\n" "\t\t[--ubi-info] [--help] [--version]\n" -"Usage 2: " PROGRAM_NAME " <MTD device node file name> [-u] [-h] [-V] [--ubi-info] [--help]\n" +"Usage 2: " PROGRAM_NAME " <MTD device node file name> [-u] [-M] [-h] [-V] [--ubi-info] [--help]\n" "\t\t[--version]\n" "Example 1: " PROGRAM_NAME " - (no arguments) print general MTD information\n" "Example 2: " PROGRAM_NAME " -m 1 - print information about MTD device number 1\n" @@ -79,6 +82,7 @@ static const char usage[] = static const struct option long_options[] = { { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' }, { .name = "ubi-info", .has_arg = 0, .flag = NULL, .val = 'u' }, + { .name = "map", .has_arg = 0, .flag = NULL, .val = 'M' }, { .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' }, @@ -90,7 +94,7 @@ static int parse_opt(int argc, char * const argv[]) while (1) { int key, error = 0; - key = getopt_long(argc, argv, "am:uhV", long_options, NULL); + key = getopt_long(argc, argv, "am:uMhV", long_options, NULL); if (key == -1) break; @@ -110,6 +114,10 @@ static int parse_opt(int argc, char * const argv[]) warnmsg("-m/--mtdn is depecated, will be removed in mtd-utils-1.4.6"); break; + case 'M': + args.map = 1; + break; + case 'h': printf("%s\n\n", doc); printf("%s\n\n", usage); @@ -139,6 +147,9 @@ static int parse_opt(int argc, char * const argv[]) args.node = NULL; } + if (args.map && !args.node) + return errmsg("-M requires MTD device node name"); + return 0; } @@ -181,6 +192,109 @@ static void print_ubi_info(const struct mtd_info *mtd_info, printf("Maximum UBI volumes count: %d\n", ui.max_volumes); } +static void print_region_map(const struct mtd_dev_info *mtd, int fd, + const region_info_t *reginfo) +{ + unsigned long start; + int i, width; + int ret_locked, errno_locked, ret_bad, errno_bad; + + printf("Eraseblock map:\n"); + + /* Figure out the number of spaces to pad w/out libm */ + for (i = 1, width = 0; i < reginfo->numblocks; i *= 10, ++width) + continue; + + /* If we don't have a fd to query, just show the bare map */ + if (fd == -1) { + ret_locked = ret_bad = -1; + errno_locked = errno_bad = ENODEV; + } else + ret_locked = ret_bad = errno_locked = errno_bad = 0; + + for (i = 0; i < reginfo->numblocks; ++i) { + start = reginfo->offset + i * reginfo->erasesize; + printf(" %*i: %08lx ", width, i, start); + + if (ret_locked != -1) { + ret_locked = mtd_is_locked(mtd, fd, i); + if (ret_locked == 1) + printf("RO "); + else + errno_locked = errno; + } + if (ret_locked != 1) + printf(" "); + + if (ret_bad != -1) { + ret_bad = mtd_is_bad(mtd, fd, i); + if (ret_bad == 1) + printf("BAD "); + else + errno_bad = errno; + } + if (ret_bad != 1) + printf(" "); + + if (((i + 1) % 4) == 0) + printf("\n"); + } + if (i % 4) + printf("\n"); + + if (ret_locked == -1 && errno_locked != EOPNOTSUPP) { + errno = errno_locked; + sys_errmsg("could not read locked block info"); + } + + if (mtd->bb_allowed && ret_bad == -1 && errno_bad != EOPNOTSUPP) { + errno = errno_bad; + sys_errmsg("could not read bad block info"); + } +} + +static void print_region_info(const struct mtd_dev_info *mtd) +{ + region_info_t reginfo; + int r, fd; + + /* If we don't have any region info, just return */ + if (!args.map && mtd->region_cnt == 0) + return; + + /* First open the device so we can query it */ + fd = open(args.node, O_RDONLY | O_CLOEXEC); + if (fd == -1) { + sys_errmsg("couldn't open MTD dev: %s", args.node); + if (mtd->region_cnt) + return; + } + + /* Walk all the regions and show the map for them */ + if (mtd->region_cnt) { + for (r = 0; r < mtd->region_cnt; ++r) { + printf("Eraseblock region %i: ", r); + if (mtd_regioninfo(fd, r, ®info) == 0) { + printf(" offset: %#x size: %#x numblocks: %#x\n", + reginfo.offset, reginfo.erasesize, + reginfo.numblocks); + if (args.map) + print_region_map(mtd, fd, ®info); + } else + printf(" info is unavailable\n"); + } + } else { + reginfo.offset = 0; + reginfo.erasesize = mtd->eb_size; + reginfo.numblocks = mtd->eb_cnt; + reginfo.regionindex = 0; + print_region_map(mtd, fd, ®info); + } + + if (fd != -1) + close(fd); +} + static int print_dev_info(libmtd_t libmtd, const struct mtd_info *mtd_info, int mtdn) { int err; @@ -229,6 +343,8 @@ static int print_dev_info(libmtd_t libmtd, const struct mtd_info *mtd_info, int if (args.ubinfo) print_ubi_info(mtd_info, &mtd); + print_region_info(&mtd); + printf("\n"); return 0; } |