summaryrefslogtreecommitdiff
path: root/ubi-utils/src/libmtd.c
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-06-02 16:11:35 +0300
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-06-02 17:06:36 +0300
commite783e75e09b4a0a519665afd7bdeaf2985e7a09c (patch)
tree911df9cc2909f8c04077f392d191fdfc8383fd7b /ubi-utils/src/libmtd.c
parenta48340c335daba441c1f01a0cfce4d2ac6b2c9e1 (diff)
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 <Artem.Bityutskiy@nokia.com>
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;