diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-04-26 09:01:12 +0300 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-05-11 12:05:50 +0300 |
commit | 32252f2b902d88f2991d260f2982b10b2016c33b (patch) | |
tree | 3081ae785d80c563837815a5b053747f0c9d1f34 /ubi-utils/src/mtdinfo.c | |
parent | e7454c3c3928ee7af7e76c0521f477881c9bf60f (diff) |
ubi-utils: add sysfs interface support and new tool
This large commit makes several things.
1. Switches libmtd to use the new sysfs interface
2. Implements new handy 'mtdinfo' utility
3. Does minore amendmends in libubi and some ubi-tools.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'ubi-utils/src/mtdinfo.c')
-rw-r--r-- | ubi-utils/src/mtdinfo.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/ubi-utils/src/mtdinfo.c b/ubi-utils/src/mtdinfo.c new file mode 100644 index 0000000..849d165 --- /dev/null +++ b/ubi-utils/src/mtdinfo.c @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2009 Nokia Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * An utility to get MTD information. + * + * Author: Artem Bityutskiy + */ + +#include <stdint.h> +#include <stdio.h> +#include <getopt.h> +#include <stdlib.h> +#include <string.h> +#include <mtd/mtd-user.h> + +#include <libubigen.h> +#include <libmtd.h> +#include "common.h" + +#define PROGRAM_VERSION "1.0" +#define PROGRAM_NAME "mtdinfo" + +/* The variables below are set by command line arguments */ +struct args { + int mtdn; + unsigned int all:1; + unsigned int ubinfo:1; + const char *node; +}; + +static struct args args = { + .mtdn = -1, + .ubinfo = 0, + .all = 0, + .node = NULL, +}; + +static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION + " - a tool to print MTD information."; + +static const char *optionsstr = +"-m, --mtdn=<MTD device number> MTD device number to get information about\n" +"-u, --ubi-info print what would UBI layout be if it was put\n" +" on this MTD device\n" +"-a, --all print information about all MTD devices\n" +"-h, --help print help message\n" +"-V, --version print program version"; + +static const char *usage = +"Usage 1: " PROGRAM_NAME " [-m <MTD device number>] [-u] [-h] [-V] [--mtdn <MTD device number>]\n" +"\t\t[--ubi-info] [--help] [--version]\n" +"Usage 2: " PROGRAM_NAME " <MTD device node file name> [-u] [-h] [-V] [--ubi-info] [--help]\n" +"\t\t[--version]\n" +"Example 1: " PROGRAM_NAME " - (no arguments) print general MTD information\n" +"Example 2: " PROGRAM_NAME " -m 1 - print information about MTD device number 1\n" +"Example 3: " PROGRAM_NAME " /dev/mtd0 - print information MTD device /dev/mtd0\n" +"Example 4: " PROGRAM_NAME " /dev/mtd0 -u - print information MTD device /dev/mtd0\n" +"\t\t\t\tand include UBI layout information\n" +"Example 5: " PROGRAM_NAME " -a - print information about all MTD devices\n" +"\t\t\tand include UBI layout information\n"; + +static const struct option long_options[] = { + { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' }, + { .name = "ubi-info", .has_arg = 0, .flag = NULL, .val = 'u' }, + { .name = "all", .has_arg = 0, .flag = NULL, .val = 'a' }, + { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, + { NULL, 0, NULL, 0}, +}; + +static int parse_opt(int argc, char * const argv[]) +{ + while (1) { + int key; + char *endp; + + key = getopt_long(argc, argv, "am:uhV", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'a': + args.all = 1; + break; + + case 'u': + args.ubinfo = 1; + break; + + case 'm': + args.mtdn = strtoul(optarg, &endp, 0); + if (*endp != '\0' || endp == optarg || args.mtdn < 0) + return errmsg("bad MTD device number: \"%s\"", optarg); + + break; + + case 'h': + fprintf(stderr, "%s\n\n", doc); + fprintf(stderr, "%s\n\n", usage); + fprintf(stderr, "%s\n", optionsstr); + exit(EXIT_SUCCESS); + + case 'V': + fprintf(stderr, "%s\n", PROGRAM_VERSION); + exit(EXIT_SUCCESS); + + case ':': + return errmsg("parameter is missing"); + + default: + fprintf(stderr, "Use -h for help\n"); + return -1; + } + } + + if (optind == argc - 1) + args.node = argv[optind]; + else if (optind < argc) + return errmsg("more then one MTD device specified (use -h for help)"); + + if (args.all && (args.node || args.mtdn != -1)) { + args.mtdn = -1; + args.node = NULL; + } + + return 0; +} + +static int translate_dev(libmtd_t libmtd, const char *node) +{ + int err; + struct mtd_dev_info mtd; + + err = mtd_get_dev_info(libmtd, node, &mtd); + if (err) { + if (errno == ENODEV) + return errmsg("\"%s\" does not correspond to any " + "existing MTD device", node); + return sys_errmsg("cannot get information about MTD " + "device \"%s\"", node); + } + + args.mtdn = mtd.dev_num; + return 0; +} + +static int print_dev_info(libmtd_t libmtd, const struct mtd_info *mtd_info, int mtdn) +{ + int err; + struct mtd_dev_info mtd; + struct ubigen_info ui; + + err = mtd_get_dev_info1(libmtd, mtdn, &mtd); + if (err) { + if (errno == ENODEV) + return errmsg("mtd%d does not correspond to any " + "existing MTD device", mtdn); + return sys_errmsg("cannot get information about MTD device %d", + mtdn); + } + + printf("mtd%d\n", mtd.dev_num); + printf("Name: %s\n", mtd.name); + printf("Type: %s\n", mtd.type_str); + printf("Eraseblock size: "); + ubiutils_print_bytes(mtd.eb_size, 0); + printf("\n"); + printf("Amount of eraseblocks: %d (", mtd.eb_cnt); + ubiutils_print_bytes(mtd.size, 0); + printf(")\n"); + printf("Minimum input/output unit size: %d %s\n", + mtd.min_io_size, mtd.min_io_size > 1 ? "bytes" : "byte"); + if (mtd_info->sysfs_supported) + printf("Sub-page size: %d %s\n", + mtd.subpage_size, + mtd.subpage_size > 1 ? "bytes" : "byte"); + else if (mtd.type == MTD_NANDFLASH) + printf("Sub-page size: unknown\n"); + + if (mtd.oob_size > 0) + printf("OOB size: %d bytes\n", + mtd.oob_size); + if (mtd.region_cnt > 0) + printf("Additional erase regions: %d\n", mtd.oob_size); + if (mtd_info->sysfs_supported) + printf("Character device major/minor: %d:%d\n", + mtd.major, mtd.minor); + printf("Bad blocks are allowed: %s\n", + mtd.bb_allowed ? "true" : "false"); + printf("Device is writable: %s\n", + mtd.writable ? "true" : "false"); + + if (!args.ubinfo) + goto out; + + if (!mtd_info->sysfs_supported) { + errmsg("cannot provide UBI info, becasue sub-page size is " + "not known"); + goto out; + } + + ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, mtd.subpage_size, + 0, 1); + printf("Default UBI VID header offset: %d\n", ui.vid_hdr_offs); + printf("Default UBI data offset: %d\n", ui.data_offs); + printf("Default UBI LEB size: "); + ubiutils_print_bytes(ui.leb_size, 0); + printf("\n"); + printf("Maximum UBI volumes count: %d\n", ui.max_volumes); + +out: + printf("\n"); + return 0; +} + +static int print_general_info(libmtd_t libmtd, const struct mtd_info *mtd_info, + int all) +{ + int i, err, first = 1; + struct mtd_dev_info mtd; + + printf("Count of MTD devices: %d\n", mtd_info->dev_count); + if (mtd_info->dev_count == 0) + return 0; + + printf("Present MTD devices: "); + for (i = mtd_info->lowest_dev_num; + i <= mtd_info->highest_dev_num; i++) { + err = mtd_get_dev_info1(libmtd, i, &mtd); + if (err == -1) { + if (errno == ENODEV) + continue; + + printf("\n"); + return sys_errmsg("libmtd failed get MTD device %d " + "information", i); + } + + if (!first) + printf(", mtd%d", i); + else { + printf("mtd%d", i); + first = 0; + } + } + printf("\n"); + printf("Sysfs interface supported: %s\n", + mtd_info->sysfs_supported ? "yes" : "no"); + + if (!all) + return 0; + + first = 1; + printf("\n"); + + for (i = mtd_info->lowest_dev_num; + i <= mtd_info->highest_dev_num; i++) { + err = print_dev_info(libmtd, mtd_info, i); + if (err) + return err; + } + + return 0; +} + +int main(int argc, char * const argv[]) +{ + int err; + libmtd_t libmtd; + struct mtd_info mtd_info; + + err = parse_opt(argc, argv); + if (err) + return -1; + + libmtd = libmtd_open(); + if (libmtd == NULL) { + if (errno == 0) + return errmsg("MTD is not present in the system"); + return sys_errmsg("cannot open libmtd"); + } + + err = mtd_get_info(libmtd, &mtd_info); + if (err) { + if (errno == ENODEV) + return errmsg("MTD is not present"); + return sys_errmsg("cannot get MTD information"); + } + + if (args.node) { + /* + * A character device was specified, translate this to MTD + * device number. + */ + err = translate_dev(libmtd, args.node); + if (err) + goto out_libmtd; + } + + if (args.mtdn == -1) + err = print_general_info(libmtd, &mtd_info, args.all); + else + err = print_dev_info(libmtd, &mtd_info, args.mtdn); + if (err) + goto out_libmtd; + + libmtd_close(libmtd); + return 0; + +out_libmtd: + libmtd_close(libmtd); + return -1; +} |