int scan_mtd(libmtd_t lib_mtd) { struct mtd_dev_info dev_info; struct mtd_info info; int i, idx = 0; if (mtd_get_info(lib_mtd, &info)) return -1; if (!info.mtd_dev_cnt) return 0; mtd_dev = xcalloc(info.mtd_dev_cnt, sizeof(mtd_dev[0])); for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; ++i) { if (!mtd_dev_present(lib_mtd, i)) continue; if (mtd_get_dev_info1(lib_mtd, i, &dev_info)) { perror("mtd_get_dev_info1"); return -1; } memcpy(&(mtd_dev[idx++].info), &dev_info, sizeof(dev_info)); } num_mtd_devices = idx; if (sort_by) qsort(mtd_dev, num_mtd_devices, sizeof(*mtd_dev), compare_mtd); return 0; }
static void test_mtd_get_info(void **state) { struct libmtd *lib = mock_libmtd_open(); struct mtd_info info; memset(&info, 0, sizeof(info)); int r = mtd_get_info(lib, &info); assert_int_equal(info.sysfs_supported, 1); assert_int_equal(info.highest_mtd_num, 0); assert_int_equal(info.lowest_mtd_num, 0); assert_int_equal(info.mtd_dev_cnt, 1); assert_int_equal(r, 0); libmtd_close(lib); (void)state; }
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.all && args.node) { int mtdn; /* * A character device was specified, translate this to MTD * device number. */ mtdn = translate_dev(libmtd, args.node); if (mtdn < 0) goto out_libmtd; err = print_dev_info(libmtd, &mtd_info, mtdn); } else err = print_general_info(libmtd, &mtd_info, args.all); if (err) goto out_libmtd; libmtd_close(libmtd); return 0; out_libmtd: libmtd_close(libmtd); return -1; }
int mtd_probe_node(libmtd_t desc, const char *node) { struct stat st; struct mtd_info info; int i, major, minor; struct libmtd *lib = (struct libmtd *)desc; if (stat(node, &st)) return sys_errmsg("cannot get information about \"%s\"", node); if (!S_ISCHR(st.st_mode)) { errmsg("\"%s\" is not a character device", node); errno = EINVAL; return -1; } major = major(st.st_rdev); minor = minor(st.st_rdev); if (mtd_get_info((libmtd_t *)lib, &info)) return -1; if (!lib->sysfs_supported) return 0; for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { int major1, minor1, ret; ret = dev_get_major(lib, i, &major1, &minor1); if (ret) { if (errno == ENOENT) continue; if (!errno) break; return -1; } if (major1 == major && minor1 == minor) return 1; } errno = 0; return -1; }
/** * dev_node2num - find UBI device number by its character device node. * @lib: MTD library descriptor * @node: name of the MTD device node * @dev_num: MTD device number is returned here * * This function returns %0 in case of success and %-1 in case of failure. */ static int dev_node2num(struct libmtd *lib, const char *node, int *dev_num) { struct stat st; int i, major, minor; struct mtd_info info; if (stat(node, &st)) return sys_errmsg("cannot get information about \"%s\"", node); if (!S_ISCHR(st.st_mode)) { errmsg("\"%s\" is not a character device", node); errno = EINVAL; return -1; } major = major(st.st_rdev); minor = minor(st.st_rdev); if (mtd_get_info((libmtd_t *)lib, &info)) return -1; for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { int major1, minor1, ret; ret = dev_get_major(lib, i, &major1, &minor1); if (ret) { if (errno == ENOENT) continue; if (!errno) break; return -1; } if (major1 == major && minor1 == minor) { errno = 0; *dev_num = i; return 0; } } errno = ENODEV; return -1; }
int main(int argc, char * const argv[]) { int err, verbose; libmtd_t libmtd; struct mtd_info mtd_info; struct mtd_dev_info mtd; libubi_t libubi; struct ubigen_info ui; struct ubi_scan_info *si; libmtd = libmtd_open(); if (!libmtd) return errmsg("MTD subsystem is not present"); err = parse_opt(argc, argv); if (err) goto out_close_mtd; err = mtd_get_info(libmtd, &mtd_info); if (err) { if (errno == ENODEV) errmsg("MTD is not present"); sys_errmsg("cannot get MTD information"); goto out_close_mtd; } err = mtd_get_dev_info(libmtd, args.node, &mtd); if (err) { sys_errmsg("cannot get information about \"%s\"", args.node); goto out_close_mtd; } if (!is_power_of_2(mtd.min_io_size)) { errmsg("min. I/O size is %d, but should be power of 2", mtd.min_io_size); goto out_close; } if (!mtd_info.sysfs_supported) { /* * Linux kernels older than 2.6.30 did not support sysfs * interface, and it is impossible to find out sub-page * size in these kernels. This is why users should * provide -s option. */ if (args.subpage_size == 0) { warnmsg("your MTD system is old and it is impossible " "to detect sub-page size. Use -s to get rid " "of this warning"); normsg("assume sub-page to be %d", mtd.subpage_size); } else { mtd.subpage_size = args.subpage_size; args.manual_subpage = 1; } } else if (args.subpage_size && args.subpage_size != mtd.subpage_size) { mtd.subpage_size = args.subpage_size; args.manual_subpage = 1; } if (args.manual_subpage) { /* Do some sanity check */ if (args.subpage_size > mtd.min_io_size) { errmsg("sub-page cannot be larger than min. I/O unit"); goto out_close; } if (mtd.min_io_size % args.subpage_size) { errmsg("min. I/O unit size should be multiple of " "sub-page size"); goto out_close; } } args.node_fd = open(args.node, O_RDWR); if (args.node_fd == -1) { sys_errmsg("cannot open \"%s\"", args.node); goto out_close_mtd; } /* Validate VID header offset if it was specified */ if (args.vid_hdr_offs != 0) { if (args.vid_hdr_offs % 8) { errmsg("VID header offset has to be multiple of min. I/O unit size"); goto out_close; } if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd.eb_size) { errmsg("bad VID header offset"); goto out_close; } } if (!mtd.writable) { errmsg("mtd%d (%s) is a read-only device", mtd.mtd_num, args.node); goto out_close; } /* Make sure this MTD device is not attached to UBI */ libubi = libubi_open(); if (libubi) { int ubi_dev_num; err = mtd_num2ubi_dev(libubi, mtd.mtd_num, &ubi_dev_num); libubi_close(libubi); if (!err) { errmsg("please, first detach mtd%d (%s) from ubi%d", mtd.mtd_num, args.node, ubi_dev_num); goto out_close; } } if (!args.quiet) { normsg_cont("mtd%d (%s), size ", mtd.mtd_num, mtd.type_str); ubiutils_print_bytes(mtd.size, 1); printf(", %d eraseblocks of ", mtd.eb_cnt); ubiutils_print_bytes(mtd.eb_size, 1); printf(", min. I/O size %d bytes\n", mtd.min_io_size); } if (args.quiet) verbose = 0; else if (args.verbose) verbose = 2; else verbose = 1; err = ubi_scan(&mtd, args.node_fd, &si, verbose); if (err) { errmsg("failed to scan mtd%d (%s)", mtd.mtd_num, args.node); goto out_close; } if (si->good_cnt == 0) { errmsg("all %d eraseblocks are bad", si->bad_cnt); goto out_free; } if (si->good_cnt < 2 && (!args.novtbl || args.image)) { errmsg("too few non-bad eraseblocks (%d) on mtd%d", si->good_cnt, mtd.mtd_num); goto out_free; } if (!args.quiet) { if (si->ok_cnt) normsg("%d eraseblocks have valid erase counter, mean value is %lld", si->ok_cnt, si->mean_ec); if (si->empty_cnt) normsg("%d eraseblocks are supposedly empty", si->empty_cnt); if (si->corrupted_cnt) normsg("%d corrupted erase counters", si->corrupted_cnt); print_bad_eraseblocks(&mtd, si); } if (si->alien_cnt) { if (!args.yes || !args.quiet) warnmsg("%d of %d eraseblocks contain non-ubifs data", si->alien_cnt, si->good_cnt); if (!args.yes && want_exit()) { if (args.yes && !args.quiet) printf("yes\n"); goto out_free; } } if (!args.override_ec && si->empty_cnt < si->good_cnt) { int percent = ((double)si->ok_cnt)/si->good_cnt * 100; /* * Make sure the majority of eraseblocks have valid * erase counters. */ if (percent < 50) { if (!args.yes || !args.quiet) warnmsg("only %d of %d eraseblocks have valid erase counter", si->ok_cnt, si->good_cnt); normsg("erase counter 0 will be used for all eraseblocks"); normsg("note, arbitrary erase counter value may be specified using -e option"); if (!args.yes && want_exit()) { if (args.yes && !args.quiet) printf("yes\n"); goto out_free; } args.ec = 0; args.override_ec = 1; } else if (percent < 95) { if (!args.yes || !args.quiet) warnmsg("only %d of %d eraseblocks have valid erase counter", si->ok_cnt, si->good_cnt); normsg("mean erase counter %lld will be used for the rest of eraseblock", si->mean_ec); if (!args.yes && want_exit()) { if (args.yes && !args.quiet) printf("yes\n"); goto out_free; } args.ec = si->mean_ec; args.override_ec = 1; } } if (!args.quiet && args.override_ec) normsg("use erase counter %lld for all eraseblocks", args.ec); ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, mtd.subpage_size, args.vid_hdr_offs, args.ubi_ver, args.image_seq); if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) { /* * Hmm, what we read from flash and what we calculated using * min. I/O unit size and sub-page size differs. */ if (!args.yes || !args.quiet) { warnmsg("VID header and data offsets on flash are %d and %d, " "which is different to requested offsets %d and %d", si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs, ui.data_offs); normsg_cont("use new offsets %d and %d? (yes/no) ", ui.vid_hdr_offs, ui.data_offs); } if (args.yes || answer_is_yes()) { if (args.yes && !args.quiet) printf("yes\n"); } else ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, 0, si->vid_hdr_offs, args.ubi_ver, args.image_seq); normsg("use offsets %d and %d", ui.vid_hdr_offs, ui.data_offs); } if (args.image) { err = flash_image(libmtd, &mtd, &ui, si); if (err < 0) goto out_free; err = format(libmtd, &mtd, &ui, si, err, 1); if (err) goto out_free; } else { err = format(libmtd, &mtd, &ui, si, 0, args.novtbl); if (err) goto out_free; } ubi_scan_free(si); close(args.node_fd); libmtd_close(libmtd); return 0; out_free: ubi_scan_free(si); out_close: close(args.node_fd); out_close_mtd: libmtd_close(libmtd); return -1; }
int scan_mtd_devices (void) { int err; struct flash_description *flash = get_flash_info(); struct mtd_info *mtd_info = &flash->mtd; libmtd_t libmtd = flash->libmtd; char blacklist[100] = { 0 }; char *token; char *saveptr; int i, index; #if defined(CONFIG_UBIBLACKLIST) strncpy(blacklist, CONFIG_UBIBLACKLIST, sizeof(blacklist)); #endif if (!libmtd) { ERROR("MTD is not present on the target"); return -1; } err = mtd_get_info(libmtd, mtd_info); if (err) { if (errno == ENODEV) ERROR("MTD is not present on the board"); return 0; } /* Allocate memory to store MTD infos */ flash->mtd_info = (struct mtd_ubi_info *)calloc( mtd_info->highest_mtd_num + 1, sizeof(struct mtd_ubi_info)); if (!flash->mtd_info) { ERROR("No enough memory for MTD structures"); return -ENOMEM; } token = strtok_r(blacklist, " ", &saveptr); if (token) { errno = 0; index = strtoul(token, NULL, 10); if (errno == 0) { ubi_insert_blacklist(index, flash); while ((token = strtok_r(NULL, " ", &saveptr))) { errno = 0; index = strtoul(token, NULL, 10); if (errno != 0) break; ubi_insert_blacklist(index, flash); } } } for (i = mtd_info->lowest_mtd_num; i <= mtd_info->highest_mtd_num; i++) { if (!mtd_dev_present(libmtd, i)) continue; err = mtd_get_dev_info1(libmtd, i, &flash->mtd_info[i].mtd); if (err) { TRACE("No information from MTD%d", i); continue; } #if defined(CONFIG_UBIVOL) if (!flash->mtd_info[i].skipubi) scan_ubi_partitions(i); #endif } return mtd_info->mtd_dev_cnt; }
int main(int argc, char * const argv[]) { int err, verbose; struct mtd_info mtd; libubi_t libubi; struct ubigen_info ui; struct ubi_scan_info *si; err = parse_opt(argc, argv); if (err) return -1; err = mtd_get_info(args.node, &mtd); if (err) return errmsg("cannot get information about \"%s\"", args.node); if (args.subpage_size == 0) args.subpage_size = mtd.min_io_size; else { if (args.subpage_size > mtd.min_io_size) { errmsg("sub-page cannot be larger than min. I/O unit"); goto out_close; } if (mtd.min_io_size % args.subpage_size) { errmsg("min. I/O unit size should be multiple of sub-page size"); goto out_close; } } /* Validate VID header offset if it was specified */ if (args.vid_hdr_offs != 0) { if (args.vid_hdr_offs % 8) { errmsg("VID header offset has to be multiple of min. I/O unit size"); goto out_close; } if (args.vid_hdr_offs + UBI_VID_HDR_SIZE > mtd.eb_size) { errmsg("bad VID header offset"); goto out_close; } } /* * Because of MTD interface limitations 'mtd_get_info()' cannot get * sub-page so we force the user to pass it via the command line. Let's * hope the user passed us something sane. */ mtd.subpage_size = args.subpage_size; if (mtd.rdonly) { errmsg("mtd%d (%s) is a read-only device", mtd.num, args.node); goto out_close; } /* Make sure this MTD device is not attached to UBI */ libubi = libubi_open(0); if (libubi) { int ubi_dev_num; err = mtd_num2ubi_dev(libubi, mtd.num, &ubi_dev_num); libubi_close(libubi); if (!err) { errmsg("please, first detach mtd%d (%s) from ubi%d", mtd.num, args.node, ubi_dev_num); goto out_close; } } if (!args.quiet) { normsg_cont("mtd%d (%s), size ", mtd.num, mtd.type_str); ubiutils_print_bytes(mtd.size, 1); printf(", %d eraseblocks of ", mtd.eb_size); ubiutils_print_bytes(mtd.eb_size, 1); printf(", min. I/O size %d bytes\n", mtd.min_io_size); } if (args.quiet) verbose = 0; else if (args.verbose) verbose = 2; else verbose = 1; err = ubi_scan(&mtd, &si, verbose); if (err) { errmsg("failed to scan mtd%d (%s)", mtd.num, args.node); goto out_close; } if (si->good_cnt == 0) { errmsg("all %d eraseblocks are bad", si->bad_cnt); goto out_free; } if (si->good_cnt < 2 && (!args.novtbl || args.image)) { errmsg("too few non-bad eraseblocks (%d) on mtd%d", si->good_cnt, mtd.num); goto out_free; } if (!args.quiet) { if (si->ok_cnt) normsg("%d eraseblocks have valid erase counter, mean value is %lld", si->ok_cnt, si->mean_ec); if (si->empty_cnt) normsg("%d eraseblocks are supposedly empty", si->empty_cnt); if (si->corrupted_cnt) normsg("%d corrupted erase counters", si->corrupted_cnt); print_bad_eraseblocks(&mtd, si); } if (si->alien_cnt) { if (!args.yes || !args.quiet) warnmsg("%d of %d eraseblocks contain non-ubifs data", si->alien_cnt, si->good_cnt); if (!args.yes && want_exit()) { if (args.yes && !args.quiet) printf("yes\n"); goto out_free; } } if (!args.override_ec && si->empty_cnt < si->good_cnt) { int percent = ((double)si->ok_cnt)/si->good_cnt * 100; /* * Make sure the majority of eraseblocks have valid * erase counters. */ if (percent < 50) { if (!args.yes || !args.quiet) warnmsg("only %d of %d eraseblocks have valid erase counter", si->ok_cnt, si->good_cnt); normsg("erase counter 0 will be used for all eraseblocks"); normsg("note, arbitrary erase counter value may be specified using -e option"); if (!args.yes && want_exit()) { if (args.yes && !args.quiet) printf("yes\n"); goto out_free; } args.ec = 0; args.override_ec = 1; } else if (percent < 95) { if (!args.yes || !args.quiet) warnmsg("only %d of %d eraseblocks have valid erase counter", si->ok_cnt, si->good_cnt); normsg("mean erase counter %lld will be used for the rest of eraseblock", si->mean_ec); if (!args.yes && want_exit()) { if (args.yes && !args.quiet) printf("yes\n"); goto out_free; } args.ec = si->mean_ec; args.override_ec = 1; } } if (!args.quiet && args.override_ec) normsg("use erase counter %lld for all eraseblocks", args.ec); ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, args.subpage_size, args.vid_hdr_offs, args.ubi_ver); if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) { /* * Hmm, what we read from flash and what we calculated using * min. I/O unit size and sub-page size differs. */ if (!args.yes || !args.quiet) { warnmsg("VID header and data offsets on flash are %d and %d, " "which is different to calculated offsets %d and %d", si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs, ui.data_offs); normsg_cont("use new offsets %d and %d? (yes/no) ", si->vid_hdr_offs, si->data_offs); } if (args.yes || answer_is_yes()) { if (args.yes && !args.quiet) printf("yes\n"); } else { ui.vid_hdr_offs = si->vid_hdr_offs; ui.data_offs = si->data_offs; } } if (args.image) { err = flash_image(&mtd, &ui, si); if (err < 0) goto out_free; err = format(&mtd, &ui, si, err, 1); if (err) goto out_free; } else { err = format(&mtd, &ui, si, 0, args.novtbl); if (err) goto out_free; } ubi_scan_free(si); close(mtd.fd); return 0; out_free: ubi_scan_free(si); out_close: close(mtd.fd); return -1; }
int scan_mtd_devices (void) { int err; struct flash_description *flash = get_flash_info(); struct mtd_info *mtd_info = &flash->mtd; struct mtd_ubi_info *mtd_ubi_info; libmtd_t libmtd = flash->libmtd; char blacklist[100] = { 0 }; char *token; char *saveptr; int i, index; #if defined(CONFIG_UBIBLACKLIST) strncpy(blacklist, CONFIG_UBIBLACKLIST, sizeof(blacklist)); #endif /* Blacklist passed on the command line has priority */ if (strlen(mtd_ubi_blacklist)) strncpy(blacklist, mtd_ubi_blacklist, sizeof(blacklist)); if (!libmtd) { ERROR("MTD is not present on the target"); return -1; } err = mtd_get_info(libmtd, mtd_info); if (err) { if (errno == ENODEV) ERROR("MTD is not present on the board"); return 0; } /* Allocate memory to store MTD infos */ flash->mtd_info = (struct mtd_ubi_info *)calloc( mtd_info->highest_mtd_num + 1, sizeof(struct mtd_ubi_info)); if (!flash->mtd_info) { ERROR("No enough memory for MTD structures"); return -ENOMEM; } token = strtok_r(blacklist, " ", &saveptr); if (token) { errno = 0; index = strtoul(token, NULL, 10); if (errno == 0) { ubi_insert_blacklist(index, flash); while ((token = strtok_r(NULL, " ", &saveptr))) { errno = 0; index = strtoul(token, NULL, 10); if (errno != 0) break; ubi_insert_blacklist(index, flash); } } } for (i = mtd_info->lowest_mtd_num; i <= mtd_info->highest_mtd_num; i++) { /* initialize data */ mtd_ubi_info = &flash->mtd_info[i]; LIST_INIT(&mtd_ubi_info->ubi_partitions); if (!mtd_dev_present(libmtd, i)) continue; err = mtd_get_dev_info1(libmtd, i, &flash->mtd_info[i].mtd); if (err) { TRACE("No information from MTD%d", i); continue; } } #if defined(CONFIG_UBIVOL) /* * Now search for MTD that are already attached */ scan_for_ubi_devices(); /* * Search for volumes in MTD that are not attached, default case */ for (i = mtd_info->lowest_mtd_num; i <= mtd_info->highest_mtd_num; i++) { if (flash->libubi && !flash->mtd_info[i].skipubi && !flash->mtd_info[i].scanned && flash->mtd_info[i].mtd.type != MTD_UBIVOLUME) scan_ubi_partitions(i); } #endif return mtd_info->mtd_dev_cnt; }