From e783e75e09b4a0a519665afd7bdeaf2985e7a09c Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 2 Jun 2009 16:11:35 +0300 Subject: libmts: recognize pre-MTD-sysfs kernels better Not-so-old linux kernel like 2.6.29 do already have "/sys/class/mtd/mtdX" directories, while very old kernels do not. But in 2.6.29 these directories do not contain any information. Anyway, the logic in libmtd which checked whether the system supports sysfs was broken, because it assumed that old systems do not even have "/sys/class/mtd/" directory. Fix this problem by checking for "/sys/class/mtd/mtdX/name". If this is present - the system really has sysfs support. This patch also adds an extra print to libmtd. Signed-off-by: Artem Bityutskiy --- ubi-utils/src/libmtd.c | 103 +++++++++++++++++++++++++++++++++++------- ubi-utils/src/libmtd_legacy.c | 9 +++- ubi-utils/src/mtdinfo.c | 7 +-- 3 files changed, 95 insertions(+), 24 deletions(-) diff --git a/ubi-utils/src/libmtd.c b/ubi-utils/src/libmtd.c index b050bea..4f1ef41 100644 --- a/ubi-utils/src/libmtd.c +++ b/ubi-utils/src/libmtd.c @@ -472,9 +472,88 @@ static int dev_node2num(struct libmtd *lib, const char *node, int *dev_num) return -1; } +/** + * sysfs_is_supported - check whether the MTD sub-system supports MTD. + * @lib: MTD library descriptor + * + * The Linux kernel MTD subsystem gained MTD support starting from kernel + * 2.6.30 and libmtd tries to use sysfs interface if possible, because the NAND + * sub-page size is available there (and not available at all in pre-sysfs + * kernels). + * + * Very old kernels did not have "/sys/class/mtd" directory. Not very old + * kernels (e.g., 2.6.29) did have "/sys/class/mtd/mtdX" directories, by there + * were no files there, e.g., the "name" file was not present. So all we can do + * is to check for a "/sys/class/mtd/mtdX/name" file. But this is not a + * reliable check, because if this is a new system with no MTD devices - we'll + * treat it as a pre-sysfs system. + */ +static int sysfs_is_supported(struct libmtd *lib) +{ + int fd, num = -1; + DIR *sysfs_mtd; + char file[strlen(lib->mtd_name) + 10]; + + sysfs_mtd = opendir(lib->sysfs_mtd); + if (!sysfs_mtd) { + if (errno == ENOENT) { + errno = 0; + return 0; + } + return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd); + } + + /* + * First of all find an "mtdX" directory. This is needed because there + * may be, for example, mtd1 but no mtd0. + */ + while (1) { + int ret, dev_num; + char tmp_buf[256]; + struct dirent *dirent; + + dirent = readdir(sysfs_mtd); + if (!dirent) + break; + + if (strlen(dirent->d_name) >= 255) { + errmsg("invalid entry in %s: \"%s\"", + lib->sysfs_mtd, dirent->d_name); + errno = EINVAL; + closedir(sysfs_mtd); + return -1; + } + + ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s", + &dev_num, tmp_buf); + if (ret == 1) { + num = dev_num; + break; + } + } + + if (closedir(sysfs_mtd)) + return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd); + + if (num == -1) + /* No mtd device, treat this as pre-sysfs system */ + return 0; + + sprintf(file, lib->mtd_name, num); + fd = open(file, O_RDONLY); + if (fd == -1) + return 0; + + if (close(fd)) { + sys_errmsg("close failed on \"%s\"", file); + return -1; + } + + return 1; +} + libmtd_t libmtd_open(void) { - int fd; struct libmtd *lib; lib = calloc(1, sizeof(struct libmtd)); @@ -489,28 +568,18 @@ libmtd_t libmtd_open(void) if (!lib->mtd) goto out_error; - /* Make sure MTD is recent enough and supports sysfs */ - fd = open(lib->sysfs_mtd, O_RDONLY); - if (fd == -1) { + lib->mtd_name = mkpath(lib->mtd, MTD_NAME); + if (!lib->mtd_name) + goto out_error; + + if (!sysfs_is_supported(lib)) { free(lib->mtd); free(lib->sysfs_mtd); - if (errno != ENOENT || legacy_libmtd_open()) { - free(lib); - return NULL; - } + free(lib->mtd_name); lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL; return lib; } - if (close(fd)) { - sys_errmsg("close failed on \"%s\"", lib->sysfs_mtd); - goto out_error; - } - - lib->mtd_name = mkpath(lib->mtd, MTD_NAME); - if (!lib->mtd_name) - goto out_error; - lib->mtd_dev = mkpath(lib->mtd, MTD_DEV); if (!lib->mtd_dev) goto out_error; diff --git a/ubi-utils/src/libmtd_legacy.c b/ubi-utils/src/libmtd_legacy.c index cd474b1..b477a4f 100644 --- a/ubi-utils/src/libmtd_legacy.c +++ b/ubi-utils/src/libmtd_legacy.c @@ -218,8 +218,13 @@ int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd) loff_t offs = 0; struct proc_parse_info pi; - if (stat(node, &st)) - return sys_errmsg("cannot open \"%s\"", node); + if (stat(node, &st)) { + sys_errmsg("cannot open \"%s\"", node); + if (errno == ENOENT) + normsg("MTD subsystem is old and does not support " + "sysfs, so MTD character device nodes have " + "to exist"); + } if (!S_ISCHR(st.st_mode)) { errno = EINVAL; diff --git a/ubi-utils/src/mtdinfo.c b/ubi-utils/src/mtdinfo.c index 849d165..a7ce834 100644 --- a/ubi-utils/src/mtdinfo.c +++ b/ubi-utils/src/mtdinfo.c @@ -238,23 +238,20 @@ static int print_general_info(libmtd_t libmtd, const struct mtd_info *mtd_info, 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); + "information", i); } if (!first) printf(", mtd%d", i); else { - printf("mtd%d", i); + printf("Present MTD devices: mtd%d", i); first = 0; } } -- cgit v1.2.3