/* * 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 #include #include #include #include #include #include #include #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 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 ] [-u] [-h] [-V] [--mtdn ]\n" "\t\t[--ubi-info] [--help] [--version]\n" "Usage 2: " PROGRAM_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, 0); 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; 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; return sys_errmsg("libmtd failed get MTD device %d " "information", i); } if (!first) printf(", mtd%d", i); else { printf("Present MTD devices: 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; }