summaryrefslogtreecommitdiff
path: root/ubi-utils/src/libmtd.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/libmtd.c')
-rw-r--r--ubi-utils/src/libmtd.c103
1 files changed, 86 insertions, 17 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;