aboutsummaryrefslogtreecommitdiff
path: root/ubi-utils
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils')
-rw-r--r--ubi-utils/src/libmtd.c103
-rw-r--r--ubi-utils/src/libmtd_legacy.c9
-rw-r--r--ubi-utils/src/mtdinfo.c7
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;
}
}