Move conditional lib files to oslib/
authorJens Axboe <axboe@fb.com>
Tue, 1 Dec 2015 02:40:58 +0000 (19:40 -0700)
committerJens Axboe <axboe@fb.com>
Tue, 1 Dec 2015 02:40:58 +0000 (19:40 -0700)
Signed-off-by: Jens Axboe <axboe@fb.com>
41 files changed:
Makefile
blktrace.c
engines/mtd.c
init.c
lib/getopt_long.c [deleted file]
lib/inet_aton.c [deleted file]
lib/inet_aton.h [deleted file]
lib/libmtd.c [deleted file]
lib/libmtd.h [deleted file]
lib/libmtd_common.h [deleted file]
lib/libmtd_int.h [deleted file]
lib/libmtd_legacy.c [deleted file]
lib/libmtd_xalloc.h [deleted file]
lib/linux-dev-lookup.c [deleted file]
lib/linux-dev-lookup.h [deleted file]
lib/strcasestr.c [deleted file]
lib/strcasestr.h [deleted file]
lib/strlcat.c [deleted file]
lib/strlcat.h [deleted file]
lib/strsep.c [deleted file]
lib/strsep.h [deleted file]
os/os-windows.h
os/os.h
oslib/getopt_long.c [new file with mode: 0644]
oslib/inet_aton.c [new file with mode: 0644]
oslib/inet_aton.h [new file with mode: 0644]
oslib/libmtd.c [new file with mode: 0644]
oslib/libmtd.h [new file with mode: 0644]
oslib/libmtd_common.h [new file with mode: 0644]
oslib/libmtd_int.h [new file with mode: 0644]
oslib/libmtd_legacy.c [new file with mode: 0644]
oslib/libmtd_xalloc.h [new file with mode: 0644]
oslib/linux-dev-lookup.c [new file with mode: 0644]
oslib/linux-dev-lookup.h [new file with mode: 0644]
oslib/strcasestr.c [new file with mode: 0644]
oslib/strcasestr.h [new file with mode: 0644]
oslib/strlcat.c [new file with mode: 0644]
oslib/strlcat.h [new file with mode: 0644]
oslib/strsep.c [new file with mode: 0644]
oslib/strsep.h [new file with mode: 0644]
t/btrace2fio.c

index 066b240ca522ac369f7cd58bb0ad108403a34a5e..d5a2095ffe9020710dd35db5e640ef5aa923643e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -36,11 +36,8 @@ ifdef CONFIG_GFIO
   PROGS += gfio
 endif
 
   PROGS += gfio
 endif
 
-SOURCE :=      lib/rbtree.c lib/rand.c lib/num2str.c lib/ieee754.c \
-               lib/strntol.c lib/prio_tree.c lib/zipf.c lib/axmap.c \
-               lib/pattern.c lib/lfsr.c lib/flist_sort.c lib/hweight.c \
-               lib/getrusage.c lib/tp.c lib/bloom.c lib/gauss.c \
-               lib/mountcheck.c lib/output_buffer.c lib/memalign.c \
+SOURCE :=      $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \
+               $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/lib/*.c)) \
                gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
                eta.c verify.c memory.c io_u.c parse.c mutex.c options.c \
                smalloc.c filehash.c profile.c debug.c engines/cpu.c \
                gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
                eta.c verify.c memory.c io_u.c parse.c mutex.c options.c \
                smalloc.c filehash.c profile.c debug.c engines/cpu.c \
@@ -48,8 +45,7 @@ SOURCE :=     lib/rbtree.c lib/rand.c lib/num2str.c lib/ieee754.c \
                server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
                gettime-thread.c helpers.c json.c idletime.c td_error.c \
                profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
                server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
                gettime-thread.c helpers.c json.c idletime.c td_error.c \
                profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
-               workqueue.c \
-               $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c))
+               workqueue.c
 
 ifdef CONFIG_LIBHDFS
   HDFSFLAGS= -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I $(FIO_LIBHDFS_INCLUDE)
 
 ifdef CONFIG_LIBHDFS
   HDFSFLAGS= -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I $(FIO_LIBHDFS_INCLUDE)
@@ -101,19 +97,19 @@ ifdef CONFIG_RBD
   SOURCE += engines/rbd.c
 endif
 ifndef CONFIG_STRSEP
   SOURCE += engines/rbd.c
 endif
 ifndef CONFIG_STRSEP
-  SOURCE += lib/strsep.c
+  SOURCE += oslib/strsep.c
 endif
 ifndef CONFIG_STRCASESTR
 endif
 ifndef CONFIG_STRCASESTR
-  SOURCE += lib/strcasestr.c
+  SOURCE += oslib/strcasestr.c
 endif
 ifndef CONFIG_STRLCAT
 endif
 ifndef CONFIG_STRLCAT
-  SOURCE += lib/strlcat.c
+  SOURCE += oslib/strlcat.c
 endif
 ifndef CONFIG_GETOPT_LONG_ONLY
 endif
 ifndef CONFIG_GETOPT_LONG_ONLY
-  SOURCE += lib/getopt_long.c
+  SOURCE += oslib/getopt_long.c
 endif
 ifndef CONFIG_INET_ATON
 endif
 ifndef CONFIG_INET_ATON
-  SOURCE += lib/inet_aton.c
+  SOURCE += oslib/inet_aton.c
 endif
 ifdef CONFIG_GFAPI
   SOURCE += engines/glusterfs.c
 endif
 ifdef CONFIG_GFAPI
   SOURCE += engines/glusterfs.c
@@ -125,19 +121,19 @@ ifdef CONFIG_GFAPI
 endif
 ifdef CONFIG_MTD
   SOURCE += engines/mtd.c
 endif
 ifdef CONFIG_MTD
   SOURCE += engines/mtd.c
-  SOURCE += lib/libmtd.c
-  SOURCE += lib/libmtd_legacy.c
+  SOURCE += oslib/libmtd.c
+  SOURCE += oslib/libmtd_legacy.c
 endif
 
 ifeq ($(CONFIG_TARGET_OS), Linux)
   SOURCE += diskutil.c fifo.c blktrace.c cgroup.c trim.c engines/sg.c \
 endif
 
 ifeq ($(CONFIG_TARGET_OS), Linux)
   SOURCE += diskutil.c fifo.c blktrace.c cgroup.c trim.c engines/sg.c \
-               engines/binject.c lib/linux-dev-lookup.c
+               engines/binject.c oslib/linux-dev-lookup.c
   LIBS += -lpthread -ldl
   LDFLAGS += -rdynamic
 endif
 ifeq ($(CONFIG_TARGET_OS), Android)
   SOURCE += diskutil.c fifo.c blktrace.c trim.c profiles/tiobench.c \
   LIBS += -lpthread -ldl
   LDFLAGS += -rdynamic
 endif
 ifeq ($(CONFIG_TARGET_OS), Android)
   SOURCE += diskutil.c fifo.c blktrace.c trim.c profiles/tiobench.c \
-               lib/linux-dev-lookup.c
+               oslib/linux-dev-lookup.c
   LIBS += -ldl
   LDFLAGS += -rdynamic
 endif
   LIBS += -ldl
   LDFLAGS += -rdynamic
 endif
@@ -217,7 +213,7 @@ T_LFSR_TEST_PROGS = t/lfsr-test
 
 ifeq ($(CONFIG_TARGET_OS), Linux)
 T_BTRACE_FIO_OBJS = t/btrace2fio.o
 
 ifeq ($(CONFIG_TARGET_OS), Linux)
 T_BTRACE_FIO_OBJS = t/btrace2fio.o
-T_BTRACE_FIO_OBJS += fifo.o lib/flist_sort.o t/log.o lib/linux-dev-lookup.o
+T_BTRACE_FIO_OBJS += fifo.o lib/flist_sort.o t/log.o oslib/linux-dev-lookup.o
 T_BTRACE_FIO_PROGS = t/fio-btrace2fio
 endif
 
 T_BTRACE_FIO_PROGS = t/fio-btrace2fio
 endif
 
index 562e126b428389af6db707b5fffde18cc922efb9..deb8b2d6d68eb465b1929fd9565cde900d9b408c 100644 (file)
@@ -11,7 +11,7 @@
 #include "flist.h"
 #include "fio.h"
 #include "blktrace_api.h"
 #include "flist.h"
 #include "fio.h"
 #include "blktrace_api.h"
-#include "lib/linux-dev-lookup.h"
+#include "oslib/linux-dev-lookup.h"
 
 #define TRACE_FIFO_SIZE        8192
 
 
 #define TRACE_FIFO_SIZE        8192
 
index 9381089aa57eb3b8a2997e6b0f29b4c53b695d57..7b92c836692f388ad3dad8b179ef9687e10694dc 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "../fio.h"
 #include "../verify.h"
 
 #include "../fio.h"
 #include "../verify.h"
-#include "../lib/libmtd.h"
+#include "../oslib/libmtd.h"
 
 libmtd_t desc;
 
 
 libmtd_t desc;
 
diff --git a/init.c b/init.c
index b7945cf35e81f0a4a1321268e55f6efd00505eee..353cc2b1743f945d2ab23c2ffaad35fe290344c7 100644 (file)
--- a/init.c
+++ b/init.c
@@ -27,7 +27,7 @@
 #include "filelock.h"
 
 #include "lib/getopt.h"
 #include "filelock.h"
 
 #include "lib/getopt.h"
-#include "lib/strcasestr.h"
+#include "oslib/strcasestr.h"
 
 #include "crc/test.h"
 
 
 #include "crc/test.h"
 
diff --git a/lib/getopt_long.c b/lib/getopt_long.c
deleted file mode 100644 (file)
index 11d879a..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * getopt.c
- *
- * getopt_long(), or at least a common subset thereof:
- *
- * - Option reordering is not supported
- * - -W foo is not supported
- * - First optstring character "-" not supported.
- *
- * This file was imported from the klibc library from hpa
- */
-
-#include <stdint.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "getopt.h"
-
-char *optarg = NULL;
-int optind = 0, opterr = 0, optopt = 0;
-
-static struct getopt_private_state {
-       const char *optptr;
-       const char *last_optstring;
-       char *const *last_argv;
-} pvt;
-
-static inline const char *option_matches(const char *arg_str,
-                                        const char *opt_name)
-{
-       while (*arg_str != '\0' && *arg_str != '=') {
-               if (*arg_str++ != *opt_name++)
-                       return NULL;
-       }
-
-       if (*opt_name)
-               return NULL;
-
-       return arg_str;
-}
-
-int getopt_long_only(int argc, char *const *argv, const char *optstring,
-               const struct option *longopts, int *longindex)
-{
-       const char *carg;
-       const char *osptr;
-       int opt;
-
-       optarg = NULL;
-
-       /* getopt() relies on a number of different global state
-          variables, which can make this really confusing if there is
-          more than one use of getopt() in the same program.  This
-          attempts to detect that situation by detecting if the
-          "optstring" or "argv" argument have changed since last time
-          we were called; if so, reinitialize the query state. */
-
-       if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
-           optind < 1 || optind > argc) {
-               /* optind doesn't match the current query */
-               pvt.last_optstring = optstring;
-               pvt.last_argv = argv;
-               optind = 1;
-               pvt.optptr = NULL;
-       }
-
-       carg = argv[optind];
-
-       /* First, eliminate all non-option cases */
-
-       if (!carg || carg[0] != '-' || !carg[1])
-               return -1;
-
-       if (carg[1] == '-') {
-               const struct option *lo;
-               const char *opt_end = NULL;
-
-               optind++;
-
-               /* Either it's a long option, or it's -- */
-               if (!carg[2]) {
-                       /* It's -- */
-                       return -1;
-               }
-
-               for (lo = longopts; lo->name; lo++) {
-                       if ((opt_end = option_matches(carg+2, lo->name)))
-                           break;
-               }
-               if (!opt_end)
-                       return '?';
-
-               if (longindex)
-                       *longindex = lo-longopts;
-
-               if (*opt_end == '=') {
-                       if (lo->has_arg)
-                               optarg = (char *)opt_end+1;
-                       else
-                               return '?';
-               } else if (lo->has_arg == 1) {
-                       if (!(optarg = argv[optind]))
-                               return '?';
-                       optind++;
-               }
-
-               if (lo->flag) {
-                       *lo->flag = lo->val;
-                       return 0;
-               } else {
-                       return lo->val;
-               }
-       }
-
-       if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
-               /* Someone frobbed optind, change to new opt. */
-               pvt.optptr = carg + 1;
-       }
-
-       opt = *pvt.optptr++;
-
-       if (opt != ':' && (osptr = strchr(optstring, opt))) {
-               if (osptr[1] == ':') {
-                       if (*pvt.optptr) {
-                               /* Argument-taking option with attached
-                                  argument */
-                               optarg = (char *)pvt.optptr;
-                               optind++;
-                       } else {
-                               /* Argument-taking option with non-attached
-                                  argument */
-                               if (osptr[2] == ':') {
-                                       if (argv[optind + 1]) {
-                                               optarg = (char *)argv[optind+1];
-                                               optind += 2;
-                                       } else {
-                                               optarg = NULL;
-                                               optind++;
-                                       }
-                                       return opt;
-                               } else if (argv[optind + 1]) {
-                                       optarg = (char *)argv[optind+1];
-                                       optind += 2;
-                               } else {
-                                       /* Missing argument */
-                                       optind++;
-                                       return (optstring[0] == ':')
-                                               ? ':' : '?';
-                               }
-                       }
-                       return opt;
-               } else {
-                       /* Non-argument-taking option */
-                       /* pvt.optptr will remember the exact position to
-                          resume at */
-                       if (!*pvt.optptr)
-                               optind++;
-                       return opt;
-               }
-       } else {
-               /* Unknown option */
-               optopt = opt;
-               if (!*pvt.optptr)
-                       optind++;
-               return '?';
-       }
-}
diff --git a/lib/inet_aton.c b/lib/inet_aton.c
deleted file mode 100644 (file)
index 7ae7db7..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "inet_aton.h"
-
-int inet_aton(const char *cp, struct in_addr *inp)
-{
-       return inet_pton(AF_INET, cp, inp);
-}
diff --git a/lib/inet_aton.h b/lib/inet_aton.h
deleted file mode 100644 (file)
index c93c87f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef FIO_INET_ATON_LIB_H
-#define FIO_INET_ATON_LIB_H
-
-#include <arpa/inet.h>
-
-int inet_aton(const char *cp, struct in_addr *inp);
-
-#endif
diff --git a/lib/libmtd.c b/lib/libmtd.c
deleted file mode 100644 (file)
index 5c9eac2..0000000
+++ /dev/null
@@ -1,1424 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006
- * Copyright (C) 2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Author: Artem Bityutskiy
- *
- * MTD library.
- */
-
-/* Imported from mtd-utils by dehrenberg */
-
-#include <limits.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <inttypes.h>
-
-#include <mtd/mtd-user.h>
-#include "libmtd.h"
-
-#include "libmtd_int.h"
-#include "libmtd_common.h"
-
-/**
- * mkpath - compose full path from 2 given components.
- * @path: the first component
- * @name: the second component
- *
- * This function returns the resulting path in case of success and %NULL in
- * case of failure.
- */
-static char *mkpath(const char *path, const char *name)
-{
-       char *n;
-       size_t len1 = strlen(path);
-       size_t len2 = strlen(name);
-
-       n = xmalloc(len1 + len2 + 6);
-
-       memcpy(n, path, len1);
-       if (n[len1 - 1] != '/')
-               n[len1++] = '/';
-
-       memcpy(n + len1, name, len2 + 1);
-       return n;
-}
-
-/**
- * read_data - read data from a file.
- * @file: the file to read from
- * @buf: the buffer to read to
- * @buf_len: buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure. Note, if the file contains more then @buf_len bytes of
- * date, this function fails with %EINVAL error code.
- */
-static int read_data(const char *file, void *buf, int buf_len)
-{
-       int fd, rd, tmp, tmp1;
-
-       fd = open(file, O_RDONLY | O_CLOEXEC);
-       if (fd == -1)
-               return -1;
-
-       rd = read(fd, buf, buf_len);
-       if (rd == -1) {
-               sys_errmsg("cannot read \"%s\"", file);
-               goto out_error;
-       }
-
-       if (rd == buf_len) {
-               errmsg("contents of \"%s\" is too long", file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       ((char *)buf)[rd] = '\0';
-
-       /* Make sure all data is read */
-       tmp1 = read(fd, &tmp, 1);
-       if (tmp1 == 1) {
-               sys_errmsg("cannot read \"%s\"", file);
-               goto out_error;
-       }
-       if (tmp1) {
-               errmsg("file \"%s\" contains too much data (> %d bytes)",
-                      file, buf_len);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (close(fd)) {
-               sys_errmsg("close failed on \"%s\"", file);
-               return -1;
-       }
-
-       return rd;
-
-out_error:
-       close(fd);
-       return -1;
-}
-
-/**
- * read_major - read major and minor numbers from a file.
- * @file: name of the file to read from
- * @major: major number is returned here
- * @minor: minor number is returned here
- *
- * This function returns % in case of success, and %-1 in case of failure.
- */
-static int read_major(const char *file, int *major, int *minor)
-{
-       int ret;
-       char buf[50];
-
-       ret = read_data(file, buf, 50);
-       if (ret < 0)
-               return ret;
-
-       ret = sscanf(buf, "%d:%d\n", major, minor);
-       if (ret != 2) {
-               errno = EINVAL;
-               return errmsg("\"%s\" does not have major:minor format", file);
-       }
-
-       if (*major < 0 || *minor < 0) {
-               errno = EINVAL;
-               return errmsg("bad major:minor %d:%d in \"%s\"",
-                             *major, *minor, file);
-       }
-
-       return 0;
-}
-
-/**
- * dev_get_major - get major and minor numbers of an MTD device.
- * @lib: libmtd descriptor
- * @mtd_num: MTD device number
- * @major: major number is returned here
- * @minor: minor number is returned here
- *
- * This function returns zero in case of success and %-1 in case of failure.
- */
-static int dev_get_major(struct libmtd *lib, int mtd_num, int *major, int *minor)
-{
-       char file[strlen(lib->mtd_dev) + 50];
-
-       sprintf(file, lib->mtd_dev, mtd_num);
-       return read_major(file, major, minor);
-}
-
-/**
- * dev_read_data - read data from an MTD device's sysfs file.
- * @patt: file pattern to read from
- * @mtd_num: MTD device number
- * @buf: buffer to read to
- * @buf_len: buffer length
- *
- * This function returns number of read bytes in case of success and %-1 in
- * case of failure.
- */
-static int dev_read_data(const char *patt, int mtd_num, void *buf, int buf_len)
-{
-       char file[strlen(patt) + 100];
-
-       sprintf(file, patt, mtd_num);
-       return read_data(file, buf, buf_len);
-}
-
-/**
- * read_hex_ll - read a hex 'long long' value from a file.
- * @file: the file to read from
- * @value: the result is stored here
- *
- * This function reads file @file and interprets its contents as hexadecimal
- * 'long long' integer. If this is not true, it fails with %EINVAL error code.
- * Returns %0 in case of success and %-1 in case of failure.
- */
-static int read_hex_ll(const char *file, long long *value)
-{
-       int fd, rd;
-       char buf[50];
-
-       fd = open(file, O_RDONLY | O_CLOEXEC);
-       if (fd == -1)
-               return -1;
-
-       rd = read(fd, buf, sizeof(buf));
-       if (rd == -1) {
-               sys_errmsg("cannot read \"%s\"", file);
-               goto out_error;
-       }
-       if (rd == sizeof(buf)) {
-               errmsg("contents of \"%s\" is too long", file);
-               errno = EINVAL;
-               goto out_error;
-       }
-       buf[rd] = '\0';
-
-       if (sscanf(buf, "%llx\n", value) != 1) {
-               errmsg("cannot read integer from \"%s\"\n", file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (*value < 0) {
-               errmsg("negative value %lld in \"%s\"", *value, file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (close(fd))
-               return sys_errmsg("close failed on \"%s\"", file);
-
-       return 0;
-
-out_error:
-       close(fd);
-       return -1;
-}
-
-/**
- * read_pos_ll - read a positive 'long long' value from a file.
- * @file: the file to read from
- * @value: the result is stored here
- *
- * This function reads file @file and interprets its contents as a positive
- * 'long long' integer. If this is not true, it fails with %EINVAL error code.
- * Returns %0 in case of success and %-1 in case of failure.
- */
-static int read_pos_ll(const char *file, long long *value)
-{
-       int fd, rd;
-       char buf[50];
-
-       fd = open(file, O_RDONLY | O_CLOEXEC);
-       if (fd == -1)
-               return -1;
-
-       rd = read(fd, buf, 50);
-       if (rd == -1) {
-               sys_errmsg("cannot read \"%s\"", file);
-               goto out_error;
-       }
-       if (rd == 50) {
-               errmsg("contents of \"%s\" is too long", file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (sscanf(buf, "%lld\n", value) != 1) {
-               errmsg("cannot read integer from \"%s\"\n", file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (*value < 0) {
-               errmsg("negative value %lld in \"%s\"", *value, file);
-               errno = EINVAL;
-               goto out_error;
-       }
-
-       if (close(fd))
-               return sys_errmsg("close failed on \"%s\"", file);
-
-       return 0;
-
-out_error:
-       close(fd);
-       return -1;
-}
-
-/**
- * read_hex_int - read an 'int' value from a file.
- * @file: the file to read from
- * @value: the result is stored here
- *
- * This function is the same as 'read_pos_ll()', but it reads an 'int'
- * value, not 'long long'.
- */
-static int read_hex_int(const char *file, int *value)
-{
-       long long res;
-
-       if (read_hex_ll(file, &res))
-               return -1;
-
-       /* Make sure the value has correct range */
-       if (res > INT_MAX || res < INT_MIN) {
-               errmsg("value %lld read from file \"%s\" is out of range",
-                      res, file);
-               errno = EINVAL;
-               return -1;
-       }
-
-       *value = res;
-       return 0;
-}
-
-/**
- * read_pos_int - read a positive 'int' value from a file.
- * @file: the file to read from
- * @value: the result is stored here
- *
- * This function is the same as 'read_pos_ll()', but it reads an 'int'
- * value, not 'long long'.
- */
-static int read_pos_int(const char *file, int *value)
-{
-       long long res;
-
-       if (read_pos_ll(file, &res))
-               return -1;
-
-       /* Make sure the value is not too big */
-       if (res > INT_MAX) {
-               errmsg("value %lld read from file \"%s\" is out of range",
-                      res, file);
-               errno = EINVAL;
-               return -1;
-       }
-
-       *value = res;
-       return 0;
-}
-
-/**
- * dev_read_hex_int - read an hex 'int' value from an MTD device sysfs file.
- * @patt: file pattern to read from
- * @mtd_num: MTD device number
- * @value: the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_hex_int(const char *patt, int mtd_num, int *value)
-{
-       char file[strlen(patt) + 50];
-
-       sprintf(file, patt, mtd_num);
-       return read_hex_int(file, value);
-}
-
-/**
- * dev_read_pos_int - read a positive 'int' value from an MTD device sysfs file.
- * @patt: file pattern to read from
- * @mtd_num: MTD device number
- * @value: the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_pos_int(const char *patt, int mtd_num, int *value)
-{
-       char file[strlen(patt) + 50];
-
-       sprintf(file, patt, mtd_num);
-       return read_pos_int(file, value);
-}
-
-/**
- * dev_read_pos_ll - read a positive 'long long' value from an MTD device sysfs file.
- * @patt: file pattern to read from
- * @mtd_num: MTD device number
- * @value: the result is stored here
- *
- * This function returns %0 in case of success and %-1 in case of failure.
- */
-static int dev_read_pos_ll(const char *patt, int mtd_num, long long *value)
-{
-       char file[strlen(patt) + 50];
-
-       sprintf(file, patt, mtd_num);
-       return read_pos_ll(file, value);
-}
-
-/**
- * type_str2int - convert MTD device type to integer.
- * @str: MTD device type string to convert
- *
- * This function converts MTD device type string @str, read from sysfs, into an
- * integer.
- */
-static int type_str2int(const char *str)
-{
-       if (!strcmp(str, "nand"))
-               return MTD_NANDFLASH;
-       if (!strcmp(str, "mlc-nand"))
-               return MTD_MLCNANDFLASH;
-       if (!strcmp(str, "nor"))
-               return MTD_NORFLASH;
-       if (!strcmp(str, "rom"))
-               return MTD_ROM;
-       if (!strcmp(str, "absent"))
-               return MTD_ABSENT;
-       if (!strcmp(str, "dataflash"))
-               return MTD_DATAFLASH;
-       if (!strcmp(str, "ram"))
-               return MTD_RAM;
-       if (!strcmp(str, "ubi"))
-               return MTD_UBIVOLUME;
-       return -1;
-}
-
-/**
- * dev_node2num - find UBI device number by its character device node.
- * @lib: MTD library descriptor
- * @node: name of the MTD device node
- * @mtd_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 *mtd_num)
-{
-       struct stat st;
-       int i, mjr, mnr;
-       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;
-       }
-
-       mjr = major(st.st_rdev);
-       mnr = minor(st.st_rdev);
-
-       if (mtd_get_info((libmtd_t *)lib, &info))
-               return -1;
-
-       for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
-               int mjr1, mnr1, ret;
-
-               ret = dev_get_major(lib, i, &mjr1, &mnr1);
-               if (ret) {
-                       if (errno == ENOENT)
-                               continue;
-                       if (!errno)
-                               break;
-                       return -1;
-               }
-
-               if (mjr1 == mjr && mnr1 == mnr) {
-                       errno = 0;
-                       *mtd_num = i;
-                       return 0;
-               }
-       }
-
-       errno = ENODEV;
-       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, mtd_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",
-                            &mtd_num, tmp_buf);
-               if (ret == 1) {
-                       num = mtd_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 | O_CLOEXEC);
-       if (fd == -1)
-               return 0;
-
-       if (close(fd)) {
-               sys_errmsg("close failed on \"%s\"", file);
-               return -1;
-       }
-
-       return 1;
-}
-
-libmtd_t libmtd_open(void)
-{
-       struct libmtd *lib;
-
-       lib = xzalloc(sizeof(*lib));
-
-       lib->offs64_ioctls = OFFS64_IOCTLS_UNKNOWN;
-
-       lib->sysfs_mtd = mkpath("/sys", SYSFS_MTD);
-       if (!lib->sysfs_mtd)
-               goto out_error;
-
-       lib->mtd = mkpath(lib->sysfs_mtd, MTD_NAME_PATT);
-       if (!lib->mtd)
-               goto out_error;
-
-       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);
-               free(lib->mtd_name);
-               lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL;
-               return lib;
-       }
-
-       lib->mtd_dev = mkpath(lib->mtd, MTD_DEV);
-       if (!lib->mtd_dev)
-               goto out_error;
-
-       lib->mtd_type = mkpath(lib->mtd, MTD_TYPE);
-       if (!lib->mtd_type)
-               goto out_error;
-
-       lib->mtd_eb_size = mkpath(lib->mtd, MTD_EB_SIZE);
-       if (!lib->mtd_eb_size)
-               goto out_error;
-
-       lib->mtd_size = mkpath(lib->mtd, MTD_SIZE);
-       if (!lib->mtd_size)
-               goto out_error;
-
-       lib->mtd_min_io_size = mkpath(lib->mtd, MTD_MIN_IO_SIZE);
-       if (!lib->mtd_min_io_size)
-               goto out_error;
-
-       lib->mtd_subpage_size = mkpath(lib->mtd, MTD_SUBPAGE_SIZE);
-       if (!lib->mtd_subpage_size)
-               goto out_error;
-
-       lib->mtd_oob_size = mkpath(lib->mtd, MTD_OOB_SIZE);
-       if (!lib->mtd_oob_size)
-               goto out_error;
-
-       lib->mtd_region_cnt = mkpath(lib->mtd, MTD_REGION_CNT);
-       if (!lib->mtd_region_cnt)
-               goto out_error;
-
-       lib->mtd_flags = mkpath(lib->mtd, MTD_FLAGS);
-       if (!lib->mtd_flags)
-               goto out_error;
-
-       lib->sysfs_supported = 1;
-       return lib;
-
-out_error:
-       libmtd_close((libmtd_t)lib);
-       return NULL;
-}
-
-void libmtd_close(libmtd_t desc)
-{
-       struct libmtd *lib = (struct libmtd *)desc;
-
-       free(lib->mtd_flags);
-       free(lib->mtd_region_cnt);
-       free(lib->mtd_oob_size);
-       free(lib->mtd_subpage_size);
-       free(lib->mtd_min_io_size);
-       free(lib->mtd_size);
-       free(lib->mtd_eb_size);
-       free(lib->mtd_type);
-       free(lib->mtd_dev);
-       free(lib->mtd_name);
-       free(lib->mtd);
-       free(lib->sysfs_mtd);
-       free(lib);
-}
-
-int mtd_dev_present(libmtd_t desc, int mtd_num) {
-       struct stat st;
-       struct libmtd *lib = (struct libmtd *)desc;
-
-       if (!lib->sysfs_supported) {
-               return legacy_dev_present(mtd_num) == 1;
-       } else {
-               char file[strlen(lib->mtd) + 10];
-
-               sprintf(file, lib->mtd, mtd_num);
-               return !stat(file, &st);
-       }
-}
-
-int mtd_get_info(libmtd_t desc, struct mtd_info *info)
-{
-       DIR *sysfs_mtd;
-       struct dirent *dirent;
-       struct libmtd *lib = (struct libmtd *)desc;
-
-       memset(info, 0, sizeof(struct mtd_info));
-
-       if (!lib->sysfs_supported)
-               return legacy_mtd_get_info(info);
-
-       info->sysfs_supported = 1;
-
-       /*
-        * We have to scan the MTD sysfs directory to identify how many MTD
-        * devices are present.
-        */
-       sysfs_mtd = opendir(lib->sysfs_mtd);
-       if (!sysfs_mtd) {
-               if (errno == ENOENT) {
-                       errno = ENODEV;
-                       return -1;
-               }
-               return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd);
-       }
-
-       info->lowest_mtd_num = INT_MAX;
-       while (1) {
-               int mtd_num, ret;
-               char tmp_buf[256];
-
-               errno = 0;
-               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;
-                       goto out_close;
-               }
-
-               ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s",
-                            &mtd_num, tmp_buf);
-               if (ret == 1) {
-                       info->mtd_dev_cnt += 1;
-                       if (mtd_num > info->highest_mtd_num)
-                               info->highest_mtd_num = mtd_num;
-                       if (mtd_num < info->lowest_mtd_num)
-                               info->lowest_mtd_num = mtd_num;
-               }
-       }
-
-       if (!dirent && errno) {
-               sys_errmsg("readdir failed on \"%s\"", lib->sysfs_mtd);
-               goto out_close;
-       }
-
-       if (closedir(sysfs_mtd))
-               return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd);
-
-       if (info->lowest_mtd_num == INT_MAX)
-               info->lowest_mtd_num = 0;
-
-       return 0;
-
-out_close:
-       closedir(sysfs_mtd);
-       return -1;
-}
-
-int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd)
-{
-       int ret;
-       struct libmtd *lib = (struct libmtd *)desc;
-
-       memset(mtd, 0, sizeof(struct mtd_dev_info));
-       mtd->mtd_num = mtd_num;
-
-       if (!mtd_dev_present(desc, mtd_num)) {
-               errno = ENODEV;
-               return -1;
-       } else if (!lib->sysfs_supported)
-               return legacy_get_dev_info1(mtd_num, mtd);
-
-       if (dev_get_major(lib, mtd_num, &mtd->major, &mtd->minor))
-               return -1;
-
-       ret = dev_read_data(lib->mtd_name, mtd_num, &mtd->name,
-                           MTD_NAME_MAX + 1);
-       if (ret < 0)
-               return -1;
-       ((char *)mtd->name)[ret - 1] = '\0';
-
-       ret = dev_read_data(lib->mtd_type, mtd_num, &mtd->type_str,
-                           MTD_TYPE_MAX + 1);
-       if (ret < 0)
-               return -1;
-       ((char *)mtd->type_str)[ret - 1] = '\0';
-
-       if (dev_read_pos_int(lib->mtd_eb_size, mtd_num, &mtd->eb_size))
-               return -1;
-       if (dev_read_pos_ll(lib->mtd_size, mtd_num, &mtd->size))
-               return -1;
-       if (dev_read_pos_int(lib->mtd_min_io_size, mtd_num, &mtd->min_io_size))
-               return -1;
-       if (dev_read_pos_int(lib->mtd_subpage_size, mtd_num, &mtd->subpage_size))
-               return -1;
-       if (dev_read_pos_int(lib->mtd_oob_size, mtd_num, &mtd->oob_size))
-               return -1;
-       if (dev_read_pos_int(lib->mtd_region_cnt, mtd_num, &mtd->region_cnt))
-               return -1;
-       if (dev_read_hex_int(lib->mtd_flags, mtd_num, &ret))
-               return -1;
-       mtd->writable = !!(ret & MTD_WRITEABLE);
-
-       mtd->eb_cnt = mtd->size / mtd->eb_size;
-       mtd->type = type_str2int(mtd->type_str);
-       mtd->bb_allowed = !!(mtd->type == MTD_NANDFLASH ||
-                               mtd->type == MTD_MLCNANDFLASH);
-
-       return 0;
-}
-
-int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd)
-{
-       int mtd_num;
-       struct libmtd *lib = (struct libmtd *)desc;
-
-       if (!lib->sysfs_supported)
-               return legacy_get_dev_info(node, mtd);
-
-       if (dev_node2num(lib, node, &mtd_num))
-               return -1;
-
-       return mtd_get_dev_info1(desc, mtd_num, mtd);
-}
-
-static inline int mtd_ioctl_error(const struct mtd_dev_info *mtd, int eb,
-                                 const char *sreq)
-{
-       return sys_errmsg("%s ioctl failed for eraseblock %d (mtd%d)",
-                         sreq, eb, mtd->mtd_num);
-}
-
-static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb)
-{
-       if (eb < 0 || eb >= mtd->eb_cnt) {
-               errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
-                      eb, mtd->mtd_num, mtd->eb_cnt);
-               errno = EINVAL;
-               return -1;
-       }
-       return 0;
-}
-
-static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req,
-                    const char *sreq)
-{
-       int ret;
-       struct erase_info_user ei;
-
-       ret = mtd_valid_erase_block(mtd, eb);
-       if (ret)
-               return ret;
-
-       ei.start = eb * mtd->eb_size;
-       ei.length = mtd->eb_size;
-
-       ret = ioctl(fd, req, &ei);
-       if (ret < 0)
-               return mtd_ioctl_error(mtd, eb, sreq);
-
-       return 0;
-}
-#define mtd_xlock(mtd, fd, eb, req) mtd_xlock(mtd, fd, eb, req, #req)
-
-int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb)
-{
-       return mtd_xlock(mtd, fd, eb, MEMLOCK);
-}
-
-int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb)
-{
-       return mtd_xlock(mtd, fd, eb, MEMUNLOCK);
-}
-
-int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
-{
-       int ret;
-       struct libmtd *lib = (struct libmtd *)desc;
-       struct erase_info_user64 ei64;
-       struct erase_info_user ei;
-
-       ret = mtd_valid_erase_block(mtd, eb);
-       if (ret)
-               return ret;
-
-       ei64.start = (__u64)eb * mtd->eb_size;
-       ei64.length = mtd->eb_size;
-
-       if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
-           lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
-               ret = ioctl(fd, MEMERASE64, &ei64);
-               if (ret == 0)
-                       return ret;
-
-               if (errno != ENOTTY ||
-                   lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN)
-                       return mtd_ioctl_error(mtd, eb, "MEMERASE64");
-
-               /*
-                * MEMERASE64 support was added in kernel version 2.6.31, so
-                * probably we are working with older kernel and this ioctl is
-                * not supported.
-                */
-               lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
-       }
-
-       if (ei64.start + ei64.length > 0xFFFFFFFF) {
-               errmsg("this system can address only %u eraseblocks",
-                      0xFFFFFFFFU / mtd->eb_size);
-               errno = EINVAL;
-               return -1;
-       }
-
-       ei.start = ei64.start;
-       ei.length = ei64.length;
-       ret = ioctl(fd, MEMERASE, &ei);
-       if (ret < 0)
-               return mtd_ioctl_error(mtd, eb, "MEMERASE");
-       return 0;
-}
-
-int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo)
-{
-       int ret;
-
-       if (regidx < 0) {
-               errno = ENODEV;
-               return -1;
-       }
-
-       reginfo->regionindex = regidx;
-
-       ret = ioctl(fd, MEMGETREGIONINFO, reginfo);
-       if (ret < 0)
-               return sys_errmsg("%s ioctl failed for erase region %d",
-                       "MEMGETREGIONINFO", regidx);
-
-       return 0;
-}
-
-int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb)
-{
-       int ret;
-       erase_info_t ei;
-
-       ei.start = eb * mtd->eb_size;
-       ei.length = mtd->eb_size;
-
-       ret = ioctl(fd, MEMISLOCKED, &ei);
-       if (ret < 0) {
-               if (errno != ENOTTY && errno != EOPNOTSUPP)
-                       return mtd_ioctl_error(mtd, eb, "MEMISLOCKED");
-               else
-                       errno = EOPNOTSUPP;
-       }
-
-       return ret;
-}
-
-/* Patterns to write to a physical eraseblock when torturing it */
-static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
-
-/**
- * check_pattern - check if buffer contains only a certain byte pattern.
- * @buf: buffer to check
- * @patt: the pattern to check
- * @size: buffer size in bytes
- *
- * This function returns %1 in there are only @patt bytes in @buf, and %0 if
- * something else was also found.
- */
-static int check_pattern(const void *buf, uint8_t patt, int size)
-{
-       int i;
-
-       for (i = 0; i < size; i++)
-               if (((const uint8_t *)buf)[i] != patt)
-                       return 0;
-       return 1;
-}
-
-int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
-{
-       int err, i, patt_count;
-       void *buf;
-
-       normsg("run torture test for PEB %d", eb);
-       patt_count = ARRAY_SIZE(patterns);
-
-       buf = xmalloc(mtd->eb_size);
-
-       for (i = 0; i < patt_count; i++) {
-               err = mtd_erase(desc, mtd, fd, eb);
-               if (err)
-                       goto out;
-
-               /* Make sure the PEB contains only 0xFF bytes */
-               err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
-               if (err)
-                       goto out;
-
-               err = check_pattern(buf, 0xFF, mtd->eb_size);
-               if (err == 0) {
-                       errmsg("erased PEB %d, but a non-0xFF byte found", eb);
-                       errno = EIO;
-                       goto out;
-               }
-
-               /* Write a pattern and check it */
-               memset(buf, patterns[i], mtd->eb_size);
-               err = mtd_write(desc, mtd, fd, eb, 0, buf, mtd->eb_size, NULL,
-                               0, 0);
-               if (err)
-                       goto out;
-
-               memset(buf, ~patterns[i], mtd->eb_size);
-               err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
-               if (err)
-                       goto out;
-
-               err = check_pattern(buf, patterns[i], mtd->eb_size);
-               if (err == 0) {
-                       errmsg("pattern %x checking failed for PEB %d",
-                               patterns[i], eb);
-                       errno = EIO;
-                       goto out;
-               }
-       }
-
-       err = 0;
-       normsg("PEB %d passed torture test, do not mark it a bad", eb);
-
-out:
-       free(buf);
-       return -1;
-}
-
-int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb)
-{
-       int ret;
-       loff_t seek;
-
-       ret = mtd_valid_erase_block(mtd, eb);
-       if (ret)
-               return ret;
-
-       if (!mtd->bb_allowed)
-               return 0;
-
-       seek = (loff_t)eb * mtd->eb_size;
-       ret = ioctl(fd, MEMGETBADBLOCK, &seek);
-       if (ret == -1)
-               return mtd_ioctl_error(mtd, eb, "MEMGETBADBLOCK");
-       return ret;
-}
-
-int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb)
-{
-       int ret;
-       loff_t seek;
-
-       if (!mtd->bb_allowed) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       ret = mtd_valid_erase_block(mtd, eb);
-       if (ret)
-               return ret;
-
-       seek = (loff_t)eb * mtd->eb_size;
-       ret = ioctl(fd, MEMSETBADBLOCK, &seek);
-       if (ret == -1)
-               return mtd_ioctl_error(mtd, eb, "MEMSETBADBLOCK");
-       return 0;
-}
-
-int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
-            void *buf, int len)
-{
-       int ret, rd = 0;
-       off_t seek;
-
-       ret = mtd_valid_erase_block(mtd, eb);
-       if (ret)
-               return ret;
-
-       if (offs < 0 || offs + len > mtd->eb_size) {
-               errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
-                      offs, len, mtd->mtd_num, mtd->eb_size);
-               errno = EINVAL;
-               return -1;
-       }
-
-       /* Seek to the beginning of the eraseblock */
-       seek = (off_t)eb * mtd->eb_size + offs;
-       if (lseek(fd, seek, SEEK_SET) != seek)
-               return sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t,
-                                 mtd->mtd_num, seek);
-
-       while (rd < len) {
-               ret = read(fd, buf, len);
-               if (ret < 0)
-                       return sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
-                                         len, mtd->mtd_num, eb, offs);
-               rd += ret;
-       }
-
-       return 0;
-}
-
-static int legacy_auto_oob_layout(const struct mtd_dev_info *mtd, int fd,
-                                 int ooblen, void *oob) {
-       struct nand_oobinfo old_oobinfo;
-       int start, len;
-       uint8_t *tmp_buf;
-
-       /* Read the current oob info */
-       if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo))
-               return sys_errmsg("MEMGETOOBSEL failed");
-
-       tmp_buf = malloc(ooblen);
-       memcpy(tmp_buf, oob, ooblen);
-
-       /*
-        * We use autoplacement and have the oobinfo with the autoplacement
-        * information from the kernel available
-        */
-       if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
-               int i, tags_pos = 0;
-               for (i = 0; old_oobinfo.oobfree[i][1]; i++) {
-                       /* Set the reserved bytes to 0xff */
-                       start = old_oobinfo.oobfree[i][0];
-                       len = old_oobinfo.oobfree[i][1];
-                       memcpy(oob + start, tmp_buf + tags_pos, len);
-                       tags_pos += len;
-               }
-       } else {
-               /* Set at least the ecc byte positions to 0xff */
-               start = old_oobinfo.eccbytes;
-               len = mtd->oob_size - start;
-               memcpy(oob + start, tmp_buf + start, len);
-       }
-
-       return 0;
-}
-
-int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
-             int offs, void *data, int len, void *oob, int ooblen,
-             uint8_t mode)
-{
-       int ret;
-       off_t seek;
-       struct mtd_write_req ops;
-
-       ret = mtd_valid_erase_block(mtd, eb);
-       if (ret)
-               return ret;
-
-       if (offs < 0 || offs + len > mtd->eb_size) {
-               errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
-                      offs, len, mtd->mtd_num, mtd->eb_size);
-               errno = EINVAL;
-               return -1;
-       }
-       if (offs % mtd->subpage_size) {
-               errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
-                      offs, mtd->mtd_num, mtd->subpage_size);
-               errno = EINVAL;
-               return -1;
-       }
-       if (len % mtd->subpage_size) {
-               errmsg("write length %d is not aligned to mtd%d min. I/O size %d",
-                      len, mtd->mtd_num, mtd->subpage_size);
-               errno = EINVAL;
-               return -1;
-       }
-
-       /* Calculate seek address */
-       seek = (off_t)eb * mtd->eb_size + offs;
-
-       if (oob) {
-               ops.start = seek;
-               ops.len = len;
-               ops.ooblen = ooblen;
-               ops.usr_data = (uint64_t)(unsigned long)data;
-               ops.usr_oob = (uint64_t)(unsigned long)oob;
-               ops.mode = mode;
-
-               ret = ioctl(fd, MEMWRITE, &ops);
-               if (ret == 0)
-                       return 0;
-               else if (errno != ENOTTY && errno != EOPNOTSUPP)
-                       return mtd_ioctl_error(mtd, eb, "MEMWRITE");
-
-               /* Fall back to old OOB ioctl() if necessary */
-               if (mode == MTD_OPS_AUTO_OOB)
-                       if (legacy_auto_oob_layout(mtd, fd, ooblen, oob))
-                               return -1;
-               if (mtd_write_oob(desc, mtd, fd, seek, ooblen, oob) < 0)
-                       return sys_errmsg("cannot write to OOB");
-       }
-       if (data) {
-               /* Seek to the beginning of the eraseblock */
-               if (lseek(fd, seek, SEEK_SET) != seek)
-                       return sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t,
-                                       mtd->mtd_num, seek);
-               ret = write(fd, data, len);
-               if (ret != len)
-                       return sys_errmsg("cannot write %d bytes to mtd%d "
-                                         "(eraseblock %d, offset %d)",
-                                         len, mtd->mtd_num, eb, offs);
-       }
-
-       return 0;
-}
-
-int do_oob_op(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
-             uint64_t start, uint64_t length, void *data, unsigned int cmd64,
-             unsigned int cmd)
-{
-       int ret, oob_offs;
-       struct mtd_oob_buf64 oob64;
-       struct mtd_oob_buf oob;
-       unsigned long long max_offs;
-       const char *cmd64_str, *cmd_str;
-       struct libmtd *lib = (struct libmtd *)desc;
-
-       if (cmd64 ==  MEMREADOOB64) {
-               cmd64_str = "MEMREADOOB64";
-               cmd_str   = "MEMREADOOB";
-       } else {
-               cmd64_str = "MEMWRITEOOB64";
-               cmd_str   = "MEMWRITEOOB";
-       }
-
-       max_offs = (unsigned long long)mtd->eb_cnt * mtd->eb_size;
-       if (start >= max_offs) {
-               errmsg("bad page address %" PRIu64 ", mtd%d has %d eraseblocks (%llu bytes)",
-                      start, mtd->mtd_num, mtd->eb_cnt, max_offs);
-               errno = EINVAL;
-               return -1;
-       }
-
-       oob_offs = start & (mtd->min_io_size - 1);
-       if (oob_offs + length > mtd->oob_size || length == 0) {
-               errmsg("Cannot write %" PRIu64 " OOB bytes to address %" PRIu64 " (OOB offset %u) - mtd%d OOB size is only %d bytes",
-                      length, start, oob_offs, mtd->mtd_num,  mtd->oob_size);
-               errno = EINVAL;
-               return -1;
-       }
-
-       oob64.start = start;
-       oob64.length = length;
-       oob64.usr_ptr = (uint64_t)(unsigned long)data;
-
-       if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
-           lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
-               ret = ioctl(fd, cmd64, &oob64);
-               if (ret == 0)
-                       return ret;
-
-               if (errno != ENOTTY ||
-                   lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) {
-                       sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
-                                  cmd64_str, mtd->mtd_num, start, start / mtd->eb_size);
-               }
-
-               /*
-                * MEMREADOOB64/MEMWRITEOOB64 support was added in kernel
-                * version 2.6.31, so probably we are working with older kernel
-                * and these ioctls are not supported.
-                */
-               lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
-       }
-
-       if (oob64.start > 0xFFFFFFFFULL) {
-               errmsg("this system can address only up to address %lu",
-                      0xFFFFFFFFUL);
-               errno = EINVAL;
-               return -1;
-       }
-
-       oob.start = oob64.start;
-       oob.length = oob64.length;
-       oob.ptr = data;
-
-       ret = ioctl(fd, cmd, &oob);
-       if (ret < 0)
-               sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
-                          cmd_str, mtd->mtd_num, start, start / mtd->eb_size);
-       return ret;
-}
-
-int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
-                uint64_t start, uint64_t length, void *data)
-{
-       return do_oob_op(desc, mtd, fd, start, length, data,
-                        MEMREADOOB64, MEMREADOOB);
-}
-
-int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
-                 uint64_t start, uint64_t length, void *data)
-{
-       return do_oob_op(desc, mtd, fd, start, length, data,
-                        MEMWRITEOOB64, MEMWRITEOOB);
-}
-
-int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
-                 const char *img_name)
-{
-       int tmp, ret, in_fd, len, written = 0;
-       off_t seek;
-       struct stat st;
-       char *buf;
-
-       ret = mtd_valid_erase_block(mtd, eb);
-       if (ret)
-               return ret;
-
-       if (offs < 0 || offs >= mtd->eb_size) {
-               errmsg("bad offset %d, mtd%d eraseblock size is %d",
-                      offs, mtd->mtd_num, mtd->eb_size);
-               errno = EINVAL;
-               return -1;
-       }
-       if (offs % mtd->subpage_size) {
-               errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
-                      offs, mtd->mtd_num, mtd->subpage_size);
-               errno = EINVAL;
-               return -1;
-       }
-
-       in_fd = open(img_name, O_RDONLY | O_CLOEXEC);
-       if (in_fd == -1)
-               return sys_errmsg("cannot open \"%s\"", img_name);
-
-       if (fstat(in_fd, &st)) {
-               sys_errmsg("cannot stat %s", img_name);
-               goto out_close;
-       }
-
-       len = st.st_size;
-       if (len % mtd->subpage_size) {
-               errmsg("size of \"%s\" is %d byte, which is not aligned to "
-                      "mtd%d min. I/O size %d", img_name, len, mtd->mtd_num,
-                      mtd->subpage_size);
-               errno = EINVAL;
-               goto out_close;
-       }
-       tmp = (offs + len + mtd->eb_size - 1) / mtd->eb_size;
-       if (eb + tmp > mtd->eb_cnt) {
-               errmsg("\"%s\" image size is %d bytes, mtd%d size is %d "
-                      "eraseblocks, the image does not fit if we write it "
-                      "starting from eraseblock %d, offset %d",
-                      img_name, len, mtd->mtd_num, mtd->eb_cnt, eb, offs);
-               errno = EINVAL;
-               goto out_close;
-       }
-
-       /* Seek to the beginning of the eraseblock */
-       seek = (off_t)eb * mtd->eb_size + offs;
-       if (lseek(fd, seek, SEEK_SET) != seek) {
-               sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t,
-                           mtd->mtd_num, seek);
-               goto out_close;
-       }
-
-       buf = xmalloc(mtd->eb_size);
-
-       while (written < len) {
-               int rd = 0;
-
-               do {
-                       ret = read(in_fd, buf, mtd->eb_size - offs - rd);
-                       if (ret == -1) {
-                               sys_errmsg("cannot read \"%s\"", img_name);
-                               goto out_free;
-                       }
-                       rd += ret;
-               } while (ret && rd < mtd->eb_size - offs);
-
-               ret = write(fd, buf, rd);
-               if (ret != rd) {
-                       sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)",
-                                  len, mtd->mtd_num, eb, offs);
-                       goto out_free;
-               }
-
-               offs = 0;
-               eb += 1;
-               written += rd;
-       }
-
-       free(buf);
-       close(in_fd);
-       return 0;
-
-out_free:
-       free(buf);
-out_close:
-       close(in_fd);
-       return -1;
-}
-
-int mtd_probe_node(libmtd_t desc, const char *node)
-{
-       struct stat st;
-       struct mtd_info info;
-       int i, mjr, mnr;
-       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;
-       }
-
-       mjr = major(st.st_rdev);
-       mnr = minor(st.st_rdev);
-
-       if (mtd_get_info((libmtd_t *)lib, &info))
-               return -1;
-
-       if (!lib->sysfs_supported)
-               return 0;
-
-       for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
-               int mjr1, mnr1, ret;
-
-               ret = dev_get_major(lib, i, &mjr1, &mnr1);
-               if (ret) {
-                       if (errno == ENOENT)
-                               continue;
-                       if (!errno)
-                               break;
-                       return -1;
-               }
-
-               if (mjr1 == mjr && mnr1 == mnr)
-                       return 1;
-       }
-
-       errno = 0;
-       return -1;
-}
diff --git a/lib/libmtd.h b/lib/libmtd.h
deleted file mode 100644 (file)
index 3625de5..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2008, 2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Author: Artem Bityutskiy
- *
- * MTD library.
- */
-
-/* Imported from mtd-utils by dehrenberg */
-
-#ifndef __LIBMTD_H__
-#define __LIBMTD_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Maximum MTD device name length */
-#define MTD_NAME_MAX 127
-/* Maximum MTD device type string length */
-#define MTD_TYPE_MAX 64
-
-/* MTD library descriptor */
-typedef void * libmtd_t;
-
-/* Forward decls */
-struct region_info_user;
-
-/**
- * @mtd_dev_cnt: count of MTD devices in system
- * @lowest_mtd_num: lowest MTD device number in system
- * @highest_mtd_num: highest MTD device number in system
- * @sysfs_supported: non-zero if sysfs is supported by MTD
- */
-struct mtd_info
-{
-       int mtd_dev_cnt;
-       int lowest_mtd_num;
-       int highest_mtd_num;
-       unsigned int sysfs_supported:1;
-};
-
-/**
- * struct mtd_dev_info - information about an MTD device.
- * @mtd_num: MTD device number
- * @major: major number of corresponding character device
- * @minor: minor number of corresponding character device
- * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
- * @type_str: static R/O flash type string
- * @name: device name
- * @size: device size in bytes
- * @eb_cnt: count of eraseblocks
- * @eb_size: eraseblock size
- * @min_io_size: minimum input/output unit size
- * @subpage_size: sub-page size
- * @oob_size: OOB size (zero if the device does not have OOB area)
- * @region_cnt: count of additional erase regions
- * @writable: zero if the device is read-only
- * @bb_allowed: non-zero if the MTD device may have bad eraseblocks
- */
-struct mtd_dev_info
-{
-       int mtd_num;
-       int major;
-       int minor;
-       int type;
-       char type_str[MTD_TYPE_MAX + 1];
-       char name[MTD_NAME_MAX + 1];
-       long long size;
-       int eb_cnt;
-       int eb_size;
-       int min_io_size;
-       int subpage_size;
-       int oob_size;
-       int region_cnt;
-       unsigned int writable:1;
-       unsigned int bb_allowed:1;
-};
-
-/**
- * libmtd_open - open MTD library.
- *
- * This function initializes and opens the MTD library and returns MTD library
- * descriptor in case of success and %NULL in case of failure. In case of
- * failure, errno contains zero if MTD is not present in the system, or
- * contains the error code if a real error happened.
- */
-libmtd_t libmtd_open(void);
-
-/**
- * libmtd_close - close MTD library.
- * @desc: MTD library descriptor
- */
-void libmtd_close(libmtd_t desc);
-
-/**
- * mtd_dev_present - check whether a MTD device is present.
- * @desc: MTD library descriptor
- * @mtd_num: MTD device number to check
- *
- * This function returns %1 if MTD device is present and %0 if not.
- */
-int mtd_dev_present(libmtd_t desc, int mtd_num);
-
-/**
- * mtd_get_info - get general MTD information.
- * @desc: MTD library descriptor
- * @info: the MTD device information is returned here
- *
- * This function fills the passed @info object with general MTD information and
- * returns %0 in case of success and %-1 in case of failure. If MTD subsystem is
- * not present in the system, errno is set to @ENODEV.
- */
-int mtd_get_info(libmtd_t desc, struct mtd_info *info);
-
-/**
- * mtd_get_dev_info - get information about an MTD device.
- * @desc: MTD library descriptor
- * @node: name of the MTD device node
- * @mtd: the MTD device information is returned here
- *
- * This function gets information about MTD device defined by the @node device
- * node file and saves this information in the @mtd object. Returns %0 in case
- * of success and %-1 in case of failure. If MTD subsystem is not present in the
- * system, or the MTD device does not exist, errno is set to @ENODEV.
- */
-int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd);
-
-/**
- * mtd_get_dev_info1 - get information about an MTD device.
- * @desc: MTD library descriptor
- * @mtd_num: MTD device number to fetch information about
- * @mtd: the MTD device information is returned here
- *
- * This function is identical to 'mtd_get_dev_info()' except that it accepts
- * MTD device number, not MTD character device.
- */
-int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd);
-
-/**
- * mtd_lock - lock eraseblocks.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to lock
- *
- * This function locks eraseblock @eb. Returns %0 in case of success and %-1
- * in case of failure.
- */
-int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_unlock - unlock eraseblocks.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to lock
- *
- * This function unlocks eraseblock @eb. Returns %0 in case of success and %-1
- * in case of failure.
- */
-int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_erase - erase an eraseblock.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to erase
- *
- * This function erases eraseblock @eb of MTD device described by @fd. Returns
- * %0 in case of success and %-1 in case of failure.
- */
-int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_regioninfo - get information about an erase region.
- * @fd: MTD device node file descriptor
- * @regidx: index of region to look up
- * @reginfo: the region information is returned here
- *
- * This function gets information about an erase region defined by the
- * @regidx index and saves this information in the @reginfo object.
- * Returns %0 in case of success and %-1 in case of failure. If the
- * @regidx is not valid or unavailable, errno is set to @ENODEV.
- */
-int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo);
-
-/**
- * mtd_is_locked - see if the specified eraseblock is locked.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to check
- *
- * This function checks to see if eraseblock @eb of MTD device described
- * by @fd is locked. Returns %0 if it is unlocked, %1 if it is locked, and
- * %-1 in case of failure. If the ioctl is not supported (support was added in
- * Linux kernel 2.6.36) or this particular device does not support it, errno is
- * set to @ENOTSUPP.
- */
-int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_torture - torture an eraseblock.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to torture
- *
- * This function tortures eraseblock @eb. Returns %0 in case of success and %-1
- * in case of failure.
- */
-int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_is_bad - check if eraseblock is bad.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to check
- *
- * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
- * and %-1 in case of failure.
- */
-int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_mark_bad - mark an eraseblock as bad.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to mark as bad
- *
- * This function marks eraseblock @eb as bad. Returns %0 in case of success and
- * %-1 in case of failure.
- */
-int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_read - read data from an MTD device.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to read from
- * @offs: offset withing the eraseblock to read from
- * @buf: buffer to read data to
- * @len: how many bytes to read
- *
- * This function reads @len bytes of data from eraseblock @eb and offset @offs
- * of the MTD device defined by @mtd and stores the read data at buffer @buf.
- * Returns %0 in case of success and %-1 in case of failure.
- */
-int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
-            void *buf, int len);
-
-/**
- * mtd_write - write data to an MTD device.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to write to
- * @offs: offset withing the eraseblock to write to
- * @data: data buffer to write
- * @len: how many data bytes to write
- * @oob: OOB buffer to write
- * @ooblen: how many OOB bytes to write
- * @mode: write mode (e.g., %MTD_OOB_PLACE, %MTD_OOB_RAW)
- *
- * This function writes @len bytes of data to eraseblock @eb and offset @offs
- * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
- * case of failure.
- *
- * Can only write to a single page at a time if writing to OOB.
- */
-int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
-             int offs, void *data, int len, void *oob, int ooblen,
-             uint8_t mode);
-
-/**
- * mtd_read_oob - read out-of-band area.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @start: page-aligned start address
- * @length: number of OOB bytes to read
- * @data: read buffer
- *
- * This function reads @length OOB bytes starting from address @start on
- * MTD device described by @fd. The address is specified as page byte offset
- * from the beginning of the MTD device. This function returns %0 in case of
- * success and %-1 in case of failure.
- */
-int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
-                uint64_t start, uint64_t length, void *data);
-
-/**
- * mtd_write_oob - write out-of-band area.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @start: page-aligned start address
- * @length: number of OOB bytes to write
- * @data: write buffer
- *
- * This function writes @length OOB bytes starting from address @start on
- * MTD device described by @fd. The address is specified as page byte offset
- * from the beginning of the MTD device. Returns %0 in case of success and %-1
- * in case of failure.
- */
-int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
-                 uint64_t start, uint64_t length, void *data);
-
-/**
- * mtd_write_img - write a file to MTD device.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to write to
- * @offs: offset withing the eraseblock to write to
- * @img_name: the file to write
- *
- * This function writes an image @img_name the MTD device defined by @mtd. @eb
- * and @offs are the starting eraseblock and offset on the MTD device. Returns
- * %0 in case of success and %-1 in case of failure.
- */
-int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
-                 const char *img_name);
-
-/**
- * mtd_probe_node - test MTD node.
- * @desc: MTD library descriptor
- * @node: the node to test
- *
- * This function tests whether @node is an MTD device node and returns %1 if it
- * is, and %-1 if it is not (errno is %ENODEV in this case) or if an error
- * occurred.
- */
-int mtd_probe_node(libmtd_t desc, const char *node);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LIBMTD_H__ */
diff --git a/lib/libmtd_common.h b/lib/libmtd_common.h
deleted file mode 100644 (file)
index a123323..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) Artem Bityutskiy, 2007, 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Imported from mtd-utils by dehrenberg */
-
-#ifndef __MTD_UTILS_COMMON_H__
-#define __MTD_UTILS_COMMON_H__
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <features.h>
-#include <inttypes.h>
-
-#ifndef PROGRAM_NAME
-# error "You must define PROGRAM_NAME before including this header"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef MIN    /* some C lib headers define this for us */
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-#define min(a, b) MIN(a, b) /* glue for linux kernel source */
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
-#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
-#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
-
-#define min_t(t,x,y) ({ \
-       typeof((x)) _x = (x); \
-       typeof((y)) _y = (y); \
-       (_x < _y) ? _x : _y; \
-})
-
-#define max_t(t,x,y) ({ \
-       typeof((x)) _x = (x); \
-       typeof((y)) _y = (y); \
-       (_x > _y) ? _x : _y; \
-})
-
-#ifndef O_CLOEXEC
-#define O_CLOEXEC 0
-#endif
-
-/* define a print format specifier for off_t */
-#ifdef __USE_FILE_OFFSET64
-#define PRIxoff_t PRIx64
-#define PRIdoff_t PRId64
-#else
-#define PRIxoff_t "l"PRIx32
-#define PRIdoff_t "l"PRId32
-#endif
-
-/* Verbose messages */
-#define bareverbose(verbose, fmt, ...) do {                        \
-       if (verbose)                                               \
-               printf(fmt, ##__VA_ARGS__);                        \
-} while(0)
-#define verbose(verbose, fmt, ...) \
-       bareverbose(verbose, "%s: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__)
-
-/* Normal messages */
-#define normsg_cont(fmt, ...) do {                                 \
-       printf("%s: " fmt, PROGRAM_NAME, ##__VA_ARGS__);           \
-} while(0)
-#define normsg(fmt, ...) do {                                      \
-       normsg_cont(fmt "\n", ##__VA_ARGS__);                      \
-} while(0)
-
-/* Error messages */
-#define errmsg(fmt, ...)  ({                                                \
-       fprintf(stderr, "%s: error!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
-       -1;                                                                 \
-})
-#define errmsg_die(fmt, ...) do {                                           \
-       exit(errmsg(fmt, ##__VA_ARGS__));                                   \
-} while(0)
-
-/* System error messages */
-#define sys_errmsg(fmt, ...)  ({                                            \
-       int _err = errno;                                                   \
-       errmsg(fmt, ##__VA_ARGS__);                                         \
-       fprintf(stderr, "%*serror %d (%s)\n", (int)sizeof(PROGRAM_NAME) + 1,\
-               "", _err, strerror(_err));                                  \
-       -1;                                                                 \
-})
-#define sys_errmsg_die(fmt, ...) do {                                       \
-       exit(sys_errmsg(fmt, ##__VA_ARGS__));                               \
-} while(0)
-
-/* Warnings */
-#define warnmsg(fmt, ...) do {                                                \
-       fprintf(stderr, "%s: warning!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
-} while(0)
-
-#if defined(__UCLIBC__)
-/* uClibc versions before 0.9.34 don't have rpmatch() */
-#if __UCLIBC_MAJOR__ == 0 && \
-               (__UCLIBC_MINOR__ < 9 || \
-               (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 34))
-#undef rpmatch
-#define rpmatch __rpmatch
-static inline int __rpmatch(const char *resp)
-{
-    return (resp[0] == 'y' || resp[0] == 'Y') ? 1 :
-       (resp[0] == 'n' || resp[0] == 'N') ? 0 : -1;
-}
-#endif
-#endif
-
-/**
- * prompt the user for confirmation
- */
-static inline bool prompt(const char *msg, bool def)
-{
-       char *line = NULL;
-       size_t len;
-       bool ret = def;
-
-       do {
-               normsg_cont("%s (%c/%c) ", msg, def ? 'Y' : 'y', def ? 'n' : 'N');
-               fflush(stdout);
-
-               while (getline(&line, &len, stdin) == -1) {
-                       printf("failed to read prompt; assuming '%s'\n",
-                               def ? "yes" : "no");
-                       break;
-               }
-
-               if (strcmp("\n", line) != 0) {
-                       switch (rpmatch(line)) {
-                       case 0: ret = false; break;
-                       case 1: ret = true; break;
-                       case -1:
-                               puts("unknown response; please try again");
-                               continue;
-                       }
-               }
-               break;
-       } while (1);
-
-       free(line);
-
-       return ret;
-}
-
-static inline int is_power_of_2(unsigned long long n)
-{
-       return (n != 0 && ((n & (n - 1)) == 0));
-}
-
-/**
- * simple_strtoX - convert a hex/dec/oct string into a number
- * @snum: buffer to convert
- * @error: set to 1 when buffer isn't fully consumed
- *
- * These functions are similar to the standard strtoX() functions, but they are
- * a little bit easier to use if you want to convert full string of digits into
- * the binary form. The typical usage:
- *
- * int error = 0;
- * unsigned long num;
- *
- * num = simple_strtoul(str, &error);
- * if (error || ... if needed, your check that num is not out of range ...)
- *     error_happened();
- */
-#define simple_strtoX(func, type) \
-static inline type simple_##func(const char *snum, int *error) \
-{ \
-       char *endptr; \
-       type ret = func(snum, &endptr, 0); \
- \
-       if (error && (!*snum || *endptr)) { \
-               errmsg("%s: unable to parse the number '%s'", #func, snum); \
-               *error = 1; \
-       } \
- \
-       return ret; \
-}
-simple_strtoX(strtol, long int)
-simple_strtoX(strtoll, long long int)
-simple_strtoX(strtoul, unsigned long int)
-simple_strtoX(strtoull, unsigned long long int)
-
-/* Simple version-printing for utils */
-#define common_print_version() \
-do { \
-       printf("%s %s\n", PROGRAM_NAME, VERSION); \
-} while (0)
-
-#include "libmtd_xalloc.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !__MTD_UTILS_COMMON_H__ */
diff --git a/lib/libmtd_int.h b/lib/libmtd_int.h
deleted file mode 100644 (file)
index cbe2ff5..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006
- * Copyright (C) 2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Author: Artem Bityutskiy
- *
- * MTD library.
- */
-
-/* Imported from mtd-utils by dehrenberg */
-
-#ifndef __LIBMTD_INT_H__
-#define __LIBMTD_INT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PROGRAM_NAME "libmtd"
-
-#define SYSFS_MTD        "class/mtd"
-#define MTD_NAME_PATT    "mtd%d"
-#define MTD_DEV          "dev"
-#define MTD_NAME         "name"
-#define MTD_TYPE         "type"
-#define MTD_EB_SIZE      "erasesize"
-#define MTD_SIZE         "size"
-#define MTD_MIN_IO_SIZE  "writesize"
-#define MTD_SUBPAGE_SIZE "subpagesize"
-#define MTD_OOB_SIZE     "oobsize"
-#define MTD_REGION_CNT   "numeraseregions"
-#define MTD_FLAGS        "flags"
-
-#define OFFS64_IOCTLS_UNKNOWN       0
-#define OFFS64_IOCTLS_NOT_SUPPORTED 1
-#define OFFS64_IOCTLS_SUPPORTED     2
-
-/**
- * libmtd - MTD library description data structure.
- * @sysfs_mtd: MTD directory in sysfs
- * @mtd: MTD device sysfs directory pattern
- * @mtd_dev: MTD device major/minor numbers file pattern
- * @mtd_name: MTD device name file pattern
- * @mtd_type: MTD device type file pattern
- * @mtd_eb_size: MTD device eraseblock size file pattern
- * @mtd_size: MTD device size file pattern
- * @mtd_min_io_size: minimum I/O unit size file pattern
- * @mtd_subpage_size: sub-page size file pattern
- * @mtd_oob_size: MTD device OOB size file pattern
- * @mtd_region_cnt: count of additional erase regions file pattern
- * @mtd_flags: MTD device flags file pattern
- * @sysfs_supported: non-zero if sysfs is supported by MTD
- * @offs64_ioctls: %OFFS64_IOCTLS_SUPPORTED if 64-bit %MEMERASE64,
- *                 %MEMREADOOB64, %MEMWRITEOOB64 MTD device ioctls are
- *                 supported, %OFFS64_IOCTLS_NOT_SUPPORTED if not, and
- *                 %OFFS64_IOCTLS_UNKNOWN if it is not known yet;
- *
- *  Note, we cannot find out whether 64-bit ioctls are supported by MTD when we
- *  are initializing the library, because this requires an MTD device node.
- *  Indeed, we have to actually call the ioctl and check for %ENOTTY to find
- *  out whether it is supported or not.
- *
- *  Thus, we leave %offs64_ioctls uninitialized in 'libmtd_open()', and
- *  initialize it later, when corresponding libmtd function is used, and when
- *  we actually have a device node and can invoke an ioctl command on it.
- */
-struct libmtd
-{
-       char *sysfs_mtd;
-       char *mtd;
-       char *mtd_dev;
-       char *mtd_name;
-       char *mtd_type;
-       char *mtd_eb_size;
-       char *mtd_size;
-       char *mtd_min_io_size;
-       char *mtd_subpage_size;
-       char *mtd_oob_size;
-       char *mtd_region_cnt;
-       char *mtd_flags;
-       unsigned int sysfs_supported:1;
-       unsigned int offs64_ioctls:2;
-};
-
-int legacy_libmtd_open(void);
-int legacy_dev_present(int mtd_num);
-int legacy_mtd_get_info(struct mtd_info *info);
-int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd);
-int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !__LIBMTD_INT_H__ */
diff --git a/lib/libmtd_legacy.c b/lib/libmtd_legacy.c
deleted file mode 100644 (file)
index 38dc2b7..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Author: Artem Bityutskiy
- *
- * This file  is part of the MTD library. Implements pre-2.6.30 kernels support,
- * where MTD did not have sysfs interface. The main limitation of the old
- * kernels was that the sub-page size was not exported to user-space, so it was
- * not possible to get sub-page size.
- */
-
-/* Imported from mtd-utils by dehrenberg */
-
-#include <limits.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <mtd/mtd-user.h>
-
-#include "libmtd.h"
-#include "libmtd_int.h"
-#include "libmtd_common.h"
-
-#define MTD_PROC_FILE "/proc/mtd"
-#define MTD_DEV_PATT  "/dev/mtd%d"
-#define MTD_DEV_MAJOR 90
-
-#define PROC_MTD_FIRST     "dev:    size   erasesize  name\n"
-#define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1)
-#define PROC_MTD_MAX_LEN   4096
-#define PROC_MTD_PATT      "mtd%d: %llx %x"
-
-/**
- * struct proc_parse_info - /proc/mtd parsing information.
- * @mtd_num: MTD device number
- * @size: device size
- * @eb_size: eraseblock size
- * @name: device name
- * @buf: contents of /proc/mtd
- * @data_size: how much data was read into @buf
- * @pos: next string in @buf to parse
- */
-struct proc_parse_info
-{
-       int mtd_num;
-       long long size;
-       char name[MTD_NAME_MAX + 1];
-       int eb_size;
-       char *buf;
-       int data_size;
-       char *next;
-};
-
-static int proc_parse_start(struct proc_parse_info *pi)
-{
-       int fd, ret;
-
-       fd = open(MTD_PROC_FILE, O_RDONLY);
-       if (fd == -1)
-               return -1;
-
-       pi->buf = xmalloc(PROC_MTD_MAX_LEN);
-
-       ret = read(fd, pi->buf, PROC_MTD_MAX_LEN);
-       if (ret == -1) {
-               sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
-               goto out_free;
-       }
-
-       if (ret < PROC_MTD_FIRST_LEN ||
-           memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) {
-               errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE,
-                      PROC_MTD_FIRST);
-               goto out_free;
-       }
-
-       pi->data_size = ret;
-       pi->next = pi->buf + PROC_MTD_FIRST_LEN;
-
-       close(fd);
-       return 0;
-
-out_free:
-       free(pi->buf);
-       close(fd);
-       return -1;
-}
-
-static int proc_parse_next(struct proc_parse_info *pi)
-{
-       int ret, len, pos = pi->next - pi->buf;
-       char *p, *p1;
-
-       if (pos >= pi->data_size) {
-               free(pi->buf);
-               return 0;
-       }
-
-       ret = sscanf(pi->next, PROC_MTD_PATT, &pi->mtd_num, &pi->size,
-                    &pi->eb_size);
-       if (ret != 3)
-               return errmsg("\"%s\" pattern not found", PROC_MTD_PATT);
-
-       p = memchr(pi->next, '\"', pi->data_size - pos);
-       if (!p)
-               return errmsg("opening \" not found");
-       p += 1;
-       pos = p - pi->buf;
-       if (pos >= pi->data_size)
-               return errmsg("opening \" not found");
-
-       p1 = memchr(p, '\"', pi->data_size - pos);
-       if (!p1)
-               return errmsg("closing \" not found");
-       pos = p1 - pi->buf;
-       if (pos >= pi->data_size)
-               return errmsg("closing \" not found");
-
-       len = p1 - p;
-       if (len > MTD_NAME_MAX)
-               return errmsg("too long mtd%d device name", pi->mtd_num);
-
-       memcpy(pi->name, p, len);
-       pi->name[len] = '\0';
-
-       if (p1[1] != '\n')
-               return errmsg("opening \"\n\" not found");
-       pi->next = p1 + 2;
-       return 1;
-}
-
-/**
- * legacy_libmtd_open - legacy version of 'libmtd_open()'.
- *
- * This function is just checks that MTD is present in the system. Returns
- * zero in case of success and %-1 in case of failure. In case of failure,
- * errno contains zero if MTD is not present in the system, or contains the
- * error code if a real error happened. This is similar to the 'libmtd_open()'
- * return conventions.
- */
-int legacy_libmtd_open(void)
-{
-       int fd;
-
-       fd = open(MTD_PROC_FILE, O_RDONLY);
-       if (fd == -1) {
-               if (errno == ENOENT)
-                       errno = 0;
-               return -1;
-       }
-
-       close(fd);
-       return 0;
-}
-
-/**
- * legacy_dev_presentl - legacy version of 'mtd_dev_present()'.
- * @info: the MTD device information is returned here
- *
- * When the kernel does not provide sysfs files for the MTD subsystem,
- * fall-back to parsing the /proc/mtd file to determine whether an mtd device
- * number @mtd_num is present.
- */
-int legacy_dev_present(int mtd_num)
-{
-       int ret;
-       struct proc_parse_info pi;
-
-       ret = proc_parse_start(&pi);
-       if (ret)
-               return -1;
-
-       while (proc_parse_next(&pi)) {
-               if (pi.mtd_num == mtd_num)
-                       return 1;
-       }
-
-       return 0;
-}
-
-/**
- * legacy_mtd_get_info - legacy version of 'mtd_get_info()'.
- * @info: the MTD device information is returned here
- *
- * This function is similar to 'mtd_get_info()' and has the same conventions.
- */
-int legacy_mtd_get_info(struct mtd_info *info)
-{
-       int ret;
-       struct proc_parse_info pi;
-
-       ret = proc_parse_start(&pi);
-       if (ret)
-               return -1;
-
-       info->lowest_mtd_num = INT_MAX;
-       while (proc_parse_next(&pi)) {
-               info->mtd_dev_cnt += 1;
-               if (pi.mtd_num > info->highest_mtd_num)
-                       info->highest_mtd_num = pi.mtd_num;
-               if (pi.mtd_num < info->lowest_mtd_num)
-                       info->lowest_mtd_num = pi.mtd_num;
-       }
-
-       return 0;
-}
-
-/**
- * legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'.
- * @node: name of the MTD device node
- * @mtd: the MTD device information is returned here
- *
- * This function is similar to 'mtd_get_dev_info()' and has the same
- * conventions.
- */
-int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd)
-{
-       struct stat st;
-       struct mtd_info_user ui;
-       int fd, ret;
-       loff_t offs = 0;
-       struct proc_parse_info pi;
-
-       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;
-               return errmsg("\"%s\" is not a character device", node);
-       }
-
-       memset(mtd, '\0', sizeof(struct mtd_dev_info));
-       mtd->major = major(st.st_rdev);
-       mtd->minor = minor(st.st_rdev);
-
-       if (mtd->major != MTD_DEV_MAJOR) {
-               errno = EINVAL;
-               return errmsg("\"%s\" has major number %d, MTD devices have "
-                             "major %d", node, mtd->major, MTD_DEV_MAJOR);
-       }
-
-       mtd->mtd_num = mtd->minor / 2;
-
-       fd = open(node, O_RDONLY);
-       if (fd == -1)
-               return sys_errmsg("cannot open \"%s\"", node);
-
-       if (ioctl(fd, MEMGETINFO, &ui)) {
-               sys_errmsg("MEMGETINFO ioctl request failed");
-               goto out_close;
-       }
-
-       ret = ioctl(fd, MEMGETBADBLOCK, &offs);
-       if (ret == -1) {
-               if (errno != EOPNOTSUPP) {
-                       sys_errmsg("MEMGETBADBLOCK ioctl failed");
-                       goto out_close;
-               }
-               errno = 0;
-               mtd->bb_allowed = 0;
-       } else
-               mtd->bb_allowed = 1;
-
-       mtd->type = ui.type;
-       mtd->size = ui.size;
-       mtd->eb_size = ui.erasesize;
-       mtd->min_io_size = ui.writesize;
-       mtd->oob_size = ui.oobsize;
-
-       if (mtd->min_io_size <= 0) {
-               errmsg("mtd%d (%s) has insane min. I/O unit size %d",
-                      mtd->mtd_num, node, mtd->min_io_size);
-               goto out_close;
-       }
-       if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
-               errmsg("mtd%d (%s) has insane eraseblock size %d",
-                      mtd->mtd_num, node, mtd->eb_size);
-               goto out_close;
-       }
-       if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
-               errmsg("mtd%d (%s) has insane size %lld",
-                      mtd->mtd_num, node, mtd->size);
-               goto out_close;
-       }
-       mtd->eb_cnt = mtd->size / mtd->eb_size;
-
-       switch(mtd->type) {
-       case MTD_ABSENT:
-               errmsg("mtd%d (%s) is removable and is not present",
-                      mtd->mtd_num, node);
-               goto out_close;
-       case MTD_RAM:
-               strcpy((char *)mtd->type_str, "ram");
-               break;
-       case MTD_ROM:
-               strcpy((char *)mtd->type_str, "rom");
-               break;
-       case MTD_NORFLASH:
-               strcpy((char *)mtd->type_str, "nor");
-               break;
-       case MTD_NANDFLASH:
-               strcpy((char *)mtd->type_str, "nand");
-               break;
-       case MTD_MLCNANDFLASH:
-               strcpy((char *)mtd->type_str, "mlc-nand");
-               break;
-       case MTD_DATAFLASH:
-               strcpy((char *)mtd->type_str, "dataflash");
-               break;
-       case MTD_UBIVOLUME:
-               strcpy((char *)mtd->type_str, "ubi");
-               break;
-       default:
-               goto out_close;
-       }
-
-       if (ui.flags & MTD_WRITEABLE)
-               mtd->writable = 1;
-       mtd->subpage_size = mtd->min_io_size;
-
-       close(fd);
-
-       /*
-        * Unfortunately, the device name is not available via ioctl, and
-        * we have to parse /proc/mtd to get it.
-        */
-       ret = proc_parse_start(&pi);
-       if (ret)
-               return -1;
-
-       while (proc_parse_next(&pi)) {
-               if (pi.mtd_num == mtd->mtd_num) {
-                       strcpy((char *)mtd->name, pi.name);
-                       return 0;
-               }
-       }
-
-       errmsg("mtd%d not found in \"%s\"", mtd->mtd_num, MTD_PROC_FILE);
-       errno = ENOENT;
-       return -1;
-
-out_close:
-       close(fd);
-       return -1;
-}
-
-/**
- * legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'.
- * @node: name of the MTD device node
- * @mtd: the MTD device information is returned here
- *
- * This function is similar to 'mtd_get_dev_info1()' and has the same
- * conventions.
- */
-int legacy_get_dev_info1(int mtd_num, struct mtd_dev_info *mtd)
-{
-       char node[sizeof(MTD_DEV_PATT) + 20];
-
-       sprintf(node, MTD_DEV_PATT, mtd_num);
-       return legacy_get_dev_info(node, mtd);
-}
diff --git a/lib/libmtd_xalloc.h b/lib/libmtd_xalloc.h
deleted file mode 100644 (file)
index 532b80f..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * memory wrappers
- *
- * Copyright (c) Artem Bityutskiy, 2007, 2008
- * Copyright 2001, 2002 Red Hat, Inc.
- *           2001 David A. Schleef <ds@lineo.com>
- *           2002 Axis Communications AB
- *           2001, 2002 Erik Andersen <andersen@codepoet.org>
- *           2004 University of Szeged, Hungary
- *           2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MTD_UTILS_XALLOC_H__
-#define __MTD_UTILS_XALLOC_H__
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Mark these functions as unused so that gcc does not emit warnings
- * when people include this header but don't use every function.
- */
-
-__attribute__((unused))
-static void *xmalloc(size_t size)
-{
-       void *ptr = malloc(size);
-
-       if (ptr == NULL && size != 0)
-               sys_errmsg_die("out of memory");
-       return ptr;
-}
-
-__attribute__((unused))
-static void *xcalloc(size_t nmemb, size_t size)
-{
-       void *ptr = calloc(nmemb, size);
-
-       if (ptr == NULL && nmemb != 0 && size != 0)
-               sys_errmsg_die("out of memory");
-       return ptr;
-}
-
-__attribute__((unused))
-static void *xzalloc(size_t size)
-{
-       return xcalloc(1, size);
-}
-
-__attribute__((unused))
-static void *xrealloc(void *ptr, size_t size)
-{
-       ptr = realloc(ptr, size);
-       if (ptr == NULL && size != 0)
-               sys_errmsg_die("out of memory");
-       return ptr;
-}
-
-__attribute__((unused))
-static char *xstrdup(const char *s)
-{
-       char *t;
-
-       if (s == NULL)
-               return NULL;
-       t = strdup(s);
-       if (t == NULL)
-               sys_errmsg_die("out of memory");
-       return t;
-}
-
-#ifdef _GNU_SOURCE
-
-__attribute__((unused))
-static int xasprintf(char **strp, const char *fmt, ...)
-{
-       int cnt;
-       va_list ap;
-
-       va_start(ap, fmt);
-       cnt = vasprintf(strp, fmt, ap);
-       va_end(ap);
-
-       if (cnt == -1)
-               sys_errmsg_die("out of memory");
-
-       return cnt;
-}
-#endif
-
-#endif /* !__MTD_UTILS_XALLOC_H__ */
diff --git a/lib/linux-dev-lookup.c b/lib/linux-dev-lookup.c
deleted file mode 100644 (file)
index 4d5f356..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "../os/os.h"
-
-int blktrace_lookup_device(const char *redirect, char *path, unsigned int maj,
-                          unsigned int min)
-{
-       struct dirent *dir;
-       struct stat st;
-       int found = 0;
-       DIR *D;
-
-       D = opendir(path);
-       if (!D)
-               return 0;
-
-       while ((dir = readdir(D)) != NULL) {
-               char full_path[256];
-
-               if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
-                       continue;
-
-               sprintf(full_path, "%s%s%s", path, FIO_OS_PATH_SEPARATOR, dir->d_name);
-               if (lstat(full_path, &st) == -1) {
-                       perror("lstat");
-                       break;
-               }
-
-               if (S_ISDIR(st.st_mode)) {
-                       found = blktrace_lookup_device(redirect, full_path,
-                                                               maj, min);
-                       if (found) {
-                               strcpy(path, full_path);
-                               break;
-                       }
-               }
-
-               if (!S_ISBLK(st.st_mode))
-                       continue;
-
-               /*
-                * If replay_redirect is set then always return this device
-                * upon lookup which overrides the device lookup based on
-                * major minor in the actual blktrace
-                */
-               if (redirect) {
-                       strcpy(path, redirect);
-                       found = 1;
-                       break;
-               }
-
-               if (maj == major(st.st_rdev) && min == minor(st.st_rdev)) {
-                       strcpy(path, full_path);
-                       found = 1;
-                       break;
-               }
-       }
-
-       closedir(D);
-       return found;
-}
diff --git a/lib/linux-dev-lookup.h b/lib/linux-dev-lookup.h
deleted file mode 100644 (file)
index 144f33a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef LINUX_DEV_LOOKUP
-#define LINUX_DEV_LOOKUP
-
-int blktrace_lookup_device(const char *redirect, char *path, unsigned int maj,
-                          unsigned int min);
-
-#endif
diff --git a/lib/strcasestr.c b/lib/strcasestr.c
deleted file mode 100644 (file)
index 92cf24c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <ctype.h>
-#include <stddef.h>
-
-char *strcasestr(const char *s1, const char *s2)
-{
-       const char *s = s1;
-       const char *p = s2;
-
-       do {
-               if (!*p)
-                       return (char *) s1;
-               if ((*p == *s) ||
-                   (tolower(*p) == tolower(*s))) {
-                       ++p;
-                       ++s;
-               } else {
-                       p = s2;
-                       if (!*s)
-                               return NULL;
-                       s = ++s1;
-               }
-       } while (1);
-
-       return *p ? NULL : (char *) s1;
-}
diff --git a/lib/strcasestr.h b/lib/strcasestr.h
deleted file mode 100644 (file)
index 43d61df..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifdef CONFIG_STRCASESTR
-
-#include <string.h>
-
-#else
-
-#ifndef FIO_STRCASESTR_H
-#define FIO_STRCASESTR_H
-
-char *strcasestr(const char *haystack, const char *needle);
-
-#endif
-#endif
diff --git a/lib/strlcat.c b/lib/strlcat.c
deleted file mode 100644 (file)
index 643d496..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <string.h>
-
-size_t strlcat(char *dst, const char *src, size_t size)
-{
-       size_t dstlen;
-       size_t srclen;
-
-       dstlen = strlen(dst);
-       size -= dstlen + 1;
-
-       /* return if no room */
-       if (!size)
-               return dstlen;
-
-       srclen = strlen(src);
-       if (srclen > size)
-               srclen = size;
-
-       memcpy(dst + dstlen, src, srclen);
-       dst[dstlen + srclen] = '\0';
-
-       return dstlen + srclen;
-}
diff --git a/lib/strlcat.h b/lib/strlcat.h
deleted file mode 100644 (file)
index baeace4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef FIO_STRLCAT_H
-#define FIO_STRLCAT_H
-
-size_t strlcat(char *dst, const char *src, size_t size);
-
-#endif
diff --git a/lib/strsep.c b/lib/strsep.c
deleted file mode 100644 (file)
index b71e9f7..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <stdio.h>
-
-char *strsep(char **stringp, const char *delim)
-{
-       char *s, *tok;
-       const char *spanp;
-       int c, sc;
-
-       s = *stringp;
-       if (!s)
-               return NULL;
-
-       tok = s;
-       do {
-               c = *s++;
-               spanp = delim;
-               do {
-                       sc = *spanp++;
-                       if (sc == c) {
-                               if (c == 0)
-                                       s = NULL;
-                               else
-                                       s[-1] = 0;
-                               *stringp = s;
-                               return tok;
-                       }
-               } while (sc != 0);
-       } while (1);
-}
diff --git a/lib/strsep.h b/lib/strsep.h
deleted file mode 100644 (file)
index 5fea5d1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef FIO_STRSEP_LIB_H
-#define FIO_STRSEP_LIB_H
-
-char *strsep(char **, const char *);
-
-#endif
index ad1c3dfcbcf08d12d9b178ba241bb7578702501a..159c086abaeb0182129181dd6a8bebe81ab0b402 100644 (file)
@@ -16,7 +16,7 @@
 #include "../file.h"
 #include "../log.h"
 #include "../lib/hweight.h"
 #include "../file.h"
 #include "../log.h"
 #include "../lib/hweight.h"
-#include "../lib/strcasestr.h"
+#include "../oslib/strcasestr.h"
 
 #include "windows/posix.h"
 
 
 #include "windows/posix.h"
 
diff --git a/os/os.h b/os/os.h
index 8e0b8e8f1d6c3deffc45d42dc1c36b19148842f8..c46d8a3d9a6811993c22039e3d9d98434d8d3c37 100644 (file)
--- a/os/os.h
+++ b/os/os.h
@@ -65,11 +65,11 @@ typedef struct aiocb os_aiocb_t;
 #endif
 
 #ifndef CONFIG_STRSEP
 #endif
 
 #ifndef CONFIG_STRSEP
-#include "../lib/strsep.h"
+#include "../oslib/strsep.h"
 #endif
 
 #ifndef CONFIG_STRLCAT
 #endif
 
 #ifndef CONFIG_STRLCAT
-#include "../lib/strlcat.h"
+#include "../oslib/strlcat.h"
 #endif
 
 #ifdef MSG_DONTWAIT
 #endif
 
 #ifdef MSG_DONTWAIT
diff --git a/oslib/getopt_long.c b/oslib/getopt_long.c
new file mode 100644 (file)
index 0000000..11d879a
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * getopt.c
+ *
+ * getopt_long(), or at least a common subset thereof:
+ *
+ * - Option reordering is not supported
+ * - -W foo is not supported
+ * - First optstring character "-" not supported.
+ *
+ * This file was imported from the klibc library from hpa
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "getopt.h"
+
+char *optarg = NULL;
+int optind = 0, opterr = 0, optopt = 0;
+
+static struct getopt_private_state {
+       const char *optptr;
+       const char *last_optstring;
+       char *const *last_argv;
+} pvt;
+
+static inline const char *option_matches(const char *arg_str,
+                                        const char *opt_name)
+{
+       while (*arg_str != '\0' && *arg_str != '=') {
+               if (*arg_str++ != *opt_name++)
+                       return NULL;
+       }
+
+       if (*opt_name)
+               return NULL;
+
+       return arg_str;
+}
+
+int getopt_long_only(int argc, char *const *argv, const char *optstring,
+               const struct option *longopts, int *longindex)
+{
+       const char *carg;
+       const char *osptr;
+       int opt;
+
+       optarg = NULL;
+
+       /* getopt() relies on a number of different global state
+          variables, which can make this really confusing if there is
+          more than one use of getopt() in the same program.  This
+          attempts to detect that situation by detecting if the
+          "optstring" or "argv" argument have changed since last time
+          we were called; if so, reinitialize the query state. */
+
+       if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+           optind < 1 || optind > argc) {
+               /* optind doesn't match the current query */
+               pvt.last_optstring = optstring;
+               pvt.last_argv = argv;
+               optind = 1;
+               pvt.optptr = NULL;
+       }
+
+       carg = argv[optind];
+
+       /* First, eliminate all non-option cases */
+
+       if (!carg || carg[0] != '-' || !carg[1])
+               return -1;
+
+       if (carg[1] == '-') {
+               const struct option *lo;
+               const char *opt_end = NULL;
+
+               optind++;
+
+               /* Either it's a long option, or it's -- */
+               if (!carg[2]) {
+                       /* It's -- */
+                       return -1;
+               }
+
+               for (lo = longopts; lo->name; lo++) {
+                       if ((opt_end = option_matches(carg+2, lo->name)))
+                           break;
+               }
+               if (!opt_end)
+                       return '?';
+
+               if (longindex)
+                       *longindex = lo-longopts;
+
+               if (*opt_end == '=') {
+                       if (lo->has_arg)
+                               optarg = (char *)opt_end+1;
+                       else
+                               return '?';
+               } else if (lo->has_arg == 1) {
+                       if (!(optarg = argv[optind]))
+                               return '?';
+                       optind++;
+               }
+
+               if (lo->flag) {
+                       *lo->flag = lo->val;
+                       return 0;
+               } else {
+                       return lo->val;
+               }
+       }
+
+       if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+               /* Someone frobbed optind, change to new opt. */
+               pvt.optptr = carg + 1;
+       }
+
+       opt = *pvt.optptr++;
+
+       if (opt != ':' && (osptr = strchr(optstring, opt))) {
+               if (osptr[1] == ':') {
+                       if (*pvt.optptr) {
+                               /* Argument-taking option with attached
+                                  argument */
+                               optarg = (char *)pvt.optptr;
+                               optind++;
+                       } else {
+                               /* Argument-taking option with non-attached
+                                  argument */
+                               if (osptr[2] == ':') {
+                                       if (argv[optind + 1]) {
+                                               optarg = (char *)argv[optind+1];
+                                               optind += 2;
+                                       } else {
+                                               optarg = NULL;
+                                               optind++;
+                                       }
+                                       return opt;
+                               } else if (argv[optind + 1]) {
+                                       optarg = (char *)argv[optind+1];
+                                       optind += 2;
+                               } else {
+                                       /* Missing argument */
+                                       optind++;
+                                       return (optstring[0] == ':')
+                                               ? ':' : '?';
+                               }
+                       }
+                       return opt;
+               } else {
+                       /* Non-argument-taking option */
+                       /* pvt.optptr will remember the exact position to
+                          resume at */
+                       if (!*pvt.optptr)
+                               optind++;
+                       return opt;
+               }
+       } else {
+               /* Unknown option */
+               optopt = opt;
+               if (!*pvt.optptr)
+                       optind++;
+               return '?';
+       }
+}
diff --git a/oslib/inet_aton.c b/oslib/inet_aton.c
new file mode 100644 (file)
index 0000000..7ae7db7
--- /dev/null
@@ -0,0 +1,6 @@
+#include "inet_aton.h"
+
+int inet_aton(const char *cp, struct in_addr *inp)
+{
+       return inet_pton(AF_INET, cp, inp);
+}
diff --git a/oslib/inet_aton.h b/oslib/inet_aton.h
new file mode 100644 (file)
index 0000000..c93c87f
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef FIO_INET_ATON_LIB_H
+#define FIO_INET_ATON_LIB_H
+
+#include <arpa/inet.h>
+
+int inet_aton(const char *cp, struct in_addr *inp);
+
+#endif
diff --git a/oslib/libmtd.c b/oslib/libmtd.c
new file mode 100644 (file)
index 0000000..5c9eac2
--- /dev/null
@@ -0,0 +1,1424 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+/* Imported from mtd-utils by dehrenberg */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <inttypes.h>
+
+#include <mtd/mtd-user.h>
+#include "libmtd.h"
+
+#include "libmtd_int.h"
+#include "libmtd_common.h"
+
+/**
+ * mkpath - compose full path from 2 given components.
+ * @path: the first component
+ * @name: the second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+       char *n;
+       size_t len1 = strlen(path);
+       size_t len2 = strlen(name);
+
+       n = xmalloc(len1 + len2 + 6);
+
+       memcpy(n, path, len1);
+       if (n[len1 - 1] != '/')
+               n[len1++] = '/';
+
+       memcpy(n + len1, name, len2 + 1);
+       return n;
+}
+
+/**
+ * read_data - read data from a file.
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure. Note, if the file contains more then @buf_len bytes of
+ * date, this function fails with %EINVAL error code.
+ */
+static int read_data(const char *file, void *buf, int buf_len)
+{
+       int fd, rd, tmp, tmp1;
+
+       fd = open(file, O_RDONLY | O_CLOEXEC);
+       if (fd == -1)
+               return -1;
+
+       rd = read(fd, buf, buf_len);
+       if (rd == -1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+
+       if (rd == buf_len) {
+               errmsg("contents of \"%s\" is too long", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       ((char *)buf)[rd] = '\0';
+
+       /* Make sure all data is read */
+       tmp1 = read(fd, &tmp, 1);
+       if (tmp1 == 1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+       if (tmp1) {
+               errmsg("file \"%s\" contains too much data (> %d bytes)",
+                      file, buf_len);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (close(fd)) {
+               sys_errmsg("close failed on \"%s\"", file);
+               return -1;
+       }
+
+       return rd;
+
+out_error:
+       close(fd);
+       return -1;
+}
+
+/**
+ * read_major - read major and minor numbers from a file.
+ * @file: name of the file to read from
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns % in case of success, and %-1 in case of failure.
+ */
+static int read_major(const char *file, int *major, int *minor)
+{
+       int ret;
+       char buf[50];
+
+       ret = read_data(file, buf, 50);
+       if (ret < 0)
+               return ret;
+
+       ret = sscanf(buf, "%d:%d\n", major, minor);
+       if (ret != 2) {
+               errno = EINVAL;
+               return errmsg("\"%s\" does not have major:minor format", file);
+       }
+
+       if (*major < 0 || *minor < 0) {
+               errno = EINVAL;
+               return errmsg("bad major:minor %d:%d in \"%s\"",
+                             *major, *minor, file);
+       }
+
+       return 0;
+}
+
+/**
+ * dev_get_major - get major and minor numbers of an MTD device.
+ * @lib: libmtd descriptor
+ * @mtd_num: MTD device number
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of success and %-1 in case of failure.
+ */
+static int dev_get_major(struct libmtd *lib, int mtd_num, int *major, int *minor)
+{
+       char file[strlen(lib->mtd_dev) + 50];
+
+       sprintf(file, lib->mtd_dev, mtd_num);
+       return read_major(file, major, minor);
+}
+
+/**
+ * dev_read_data - read data from an MTD device's sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @buf: buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int dev_read_data(const char *patt, int mtd_num, void *buf, int buf_len)
+{
+       char file[strlen(patt) + 100];
+
+       sprintf(file, patt, mtd_num);
+       return read_data(file, buf, buf_len);
+}
+
+/**
+ * read_hex_ll - read a hex 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as hexadecimal
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_hex_ll(const char *file, long long *value)
+{
+       int fd, rd;
+       char buf[50];
+
+       fd = open(file, O_RDONLY | O_CLOEXEC);
+       if (fd == -1)
+               return -1;
+
+       rd = read(fd, buf, sizeof(buf));
+       if (rd == -1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+       if (rd == sizeof(buf)) {
+               errmsg("contents of \"%s\" is too long", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+       buf[rd] = '\0';
+
+       if (sscanf(buf, "%llx\n", value) != 1) {
+               errmsg("cannot read integer from \"%s\"\n", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (*value < 0) {
+               errmsg("negative value %lld in \"%s\"", *value, file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (close(fd))
+               return sys_errmsg("close failed on \"%s\"", file);
+
+       return 0;
+
+out_error:
+       close(fd);
+       return -1;
+}
+
+/**
+ * read_pos_ll - read a positive 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as a positive
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_pos_ll(const char *file, long long *value)
+{
+       int fd, rd;
+       char buf[50];
+
+       fd = open(file, O_RDONLY | O_CLOEXEC);
+       if (fd == -1)
+               return -1;
+
+       rd = read(fd, buf, 50);
+       if (rd == -1) {
+               sys_errmsg("cannot read \"%s\"", file);
+               goto out_error;
+       }
+       if (rd == 50) {
+               errmsg("contents of \"%s\" is too long", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (sscanf(buf, "%lld\n", value) != 1) {
+               errmsg("cannot read integer from \"%s\"\n", file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (*value < 0) {
+               errmsg("negative value %lld in \"%s\"", *value, file);
+               errno = EINVAL;
+               goto out_error;
+       }
+
+       if (close(fd))
+               return sys_errmsg("close failed on \"%s\"", file);
+
+       return 0;
+
+out_error:
+       close(fd);
+       return -1;
+}
+
+/**
+ * read_hex_int - read an 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_pos_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_hex_int(const char *file, int *value)
+{
+       long long res;
+
+       if (read_hex_ll(file, &res))
+               return -1;
+
+       /* Make sure the value has correct range */
+       if (res > INT_MAX || res < INT_MIN) {
+               errmsg("value %lld read from file \"%s\" is out of range",
+                      res, file);
+               errno = EINVAL;
+               return -1;
+       }
+
+       *value = res;
+       return 0;
+}
+
+/**
+ * read_pos_int - read a positive 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_pos_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_pos_int(const char *file, int *value)
+{
+       long long res;
+
+       if (read_pos_ll(file, &res))
+               return -1;
+
+       /* Make sure the value is not too big */
+       if (res > INT_MAX) {
+               errmsg("value %lld read from file \"%s\" is out of range",
+                      res, file);
+               errno = EINVAL;
+               return -1;
+       }
+
+       *value = res;
+       return 0;
+}
+
+/**
+ * dev_read_hex_int - read an hex 'int' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_hex_int(const char *patt, int mtd_num, int *value)
+{
+       char file[strlen(patt) + 50];
+
+       sprintf(file, patt, mtd_num);
+       return read_hex_int(file, value);
+}
+
+/**
+ * dev_read_pos_int - read a positive 'int' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_pos_int(const char *patt, int mtd_num, int *value)
+{
+       char file[strlen(patt) + 50];
+
+       sprintf(file, patt, mtd_num);
+       return read_pos_int(file, value);
+}
+
+/**
+ * dev_read_pos_ll - read a positive 'long long' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_pos_ll(const char *patt, int mtd_num, long long *value)
+{
+       char file[strlen(patt) + 50];
+
+       sprintf(file, patt, mtd_num);
+       return read_pos_ll(file, value);
+}
+
+/**
+ * type_str2int - convert MTD device type to integer.
+ * @str: MTD device type string to convert
+ *
+ * This function converts MTD device type string @str, read from sysfs, into an
+ * integer.
+ */
+static int type_str2int(const char *str)
+{
+       if (!strcmp(str, "nand"))
+               return MTD_NANDFLASH;
+       if (!strcmp(str, "mlc-nand"))
+               return MTD_MLCNANDFLASH;
+       if (!strcmp(str, "nor"))
+               return MTD_NORFLASH;
+       if (!strcmp(str, "rom"))
+               return MTD_ROM;
+       if (!strcmp(str, "absent"))
+               return MTD_ABSENT;
+       if (!strcmp(str, "dataflash"))
+               return MTD_DATAFLASH;
+       if (!strcmp(str, "ram"))
+               return MTD_RAM;
+       if (!strcmp(str, "ubi"))
+               return MTD_UBIVOLUME;
+       return -1;
+}
+
+/**
+ * dev_node2num - find UBI device number by its character device node.
+ * @lib: MTD library descriptor
+ * @node: name of the MTD device node
+ * @mtd_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 *mtd_num)
+{
+       struct stat st;
+       int i, mjr, mnr;
+       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;
+       }
+
+       mjr = major(st.st_rdev);
+       mnr = minor(st.st_rdev);
+
+       if (mtd_get_info((libmtd_t *)lib, &info))
+               return -1;
+
+       for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
+               int mjr1, mnr1, ret;
+
+               ret = dev_get_major(lib, i, &mjr1, &mnr1);
+               if (ret) {
+                       if (errno == ENOENT)
+                               continue;
+                       if (!errno)
+                               break;
+                       return -1;
+               }
+
+               if (mjr1 == mjr && mnr1 == mnr) {
+                       errno = 0;
+                       *mtd_num = i;
+                       return 0;
+               }
+       }
+
+       errno = ENODEV;
+       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, mtd_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",
+                            &mtd_num, tmp_buf);
+               if (ret == 1) {
+                       num = mtd_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 | O_CLOEXEC);
+       if (fd == -1)
+               return 0;
+
+       if (close(fd)) {
+               sys_errmsg("close failed on \"%s\"", file);
+               return -1;
+       }
+
+       return 1;
+}
+
+libmtd_t libmtd_open(void)
+{
+       struct libmtd *lib;
+
+       lib = xzalloc(sizeof(*lib));
+
+       lib->offs64_ioctls = OFFS64_IOCTLS_UNKNOWN;
+
+       lib->sysfs_mtd = mkpath("/sys", SYSFS_MTD);
+       if (!lib->sysfs_mtd)
+               goto out_error;
+
+       lib->mtd = mkpath(lib->sysfs_mtd, MTD_NAME_PATT);
+       if (!lib->mtd)
+               goto out_error;
+
+       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);
+               free(lib->mtd_name);
+               lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL;
+               return lib;
+       }
+
+       lib->mtd_dev = mkpath(lib->mtd, MTD_DEV);
+       if (!lib->mtd_dev)
+               goto out_error;
+
+       lib->mtd_type = mkpath(lib->mtd, MTD_TYPE);
+       if (!lib->mtd_type)
+               goto out_error;
+
+       lib->mtd_eb_size = mkpath(lib->mtd, MTD_EB_SIZE);
+       if (!lib->mtd_eb_size)
+               goto out_error;
+
+       lib->mtd_size = mkpath(lib->mtd, MTD_SIZE);
+       if (!lib->mtd_size)
+               goto out_error;
+
+       lib->mtd_min_io_size = mkpath(lib->mtd, MTD_MIN_IO_SIZE);
+       if (!lib->mtd_min_io_size)
+               goto out_error;
+
+       lib->mtd_subpage_size = mkpath(lib->mtd, MTD_SUBPAGE_SIZE);
+       if (!lib->mtd_subpage_size)
+               goto out_error;
+
+       lib->mtd_oob_size = mkpath(lib->mtd, MTD_OOB_SIZE);
+       if (!lib->mtd_oob_size)
+               goto out_error;
+
+       lib->mtd_region_cnt = mkpath(lib->mtd, MTD_REGION_CNT);
+       if (!lib->mtd_region_cnt)
+               goto out_error;
+
+       lib->mtd_flags = mkpath(lib->mtd, MTD_FLAGS);
+       if (!lib->mtd_flags)
+               goto out_error;
+
+       lib->sysfs_supported = 1;
+       return lib;
+
+out_error:
+       libmtd_close((libmtd_t)lib);
+       return NULL;
+}
+
+void libmtd_close(libmtd_t desc)
+{
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       free(lib->mtd_flags);
+       free(lib->mtd_region_cnt);
+       free(lib->mtd_oob_size);
+       free(lib->mtd_subpage_size);
+       free(lib->mtd_min_io_size);
+       free(lib->mtd_size);
+       free(lib->mtd_eb_size);
+       free(lib->mtd_type);
+       free(lib->mtd_dev);
+       free(lib->mtd_name);
+       free(lib->mtd);
+       free(lib->sysfs_mtd);
+       free(lib);
+}
+
+int mtd_dev_present(libmtd_t desc, int mtd_num) {
+       struct stat st;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       if (!lib->sysfs_supported) {
+               return legacy_dev_present(mtd_num) == 1;
+       } else {
+               char file[strlen(lib->mtd) + 10];
+
+               sprintf(file, lib->mtd, mtd_num);
+               return !stat(file, &st);
+       }
+}
+
+int mtd_get_info(libmtd_t desc, struct mtd_info *info)
+{
+       DIR *sysfs_mtd;
+       struct dirent *dirent;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       memset(info, 0, sizeof(struct mtd_info));
+
+       if (!lib->sysfs_supported)
+               return legacy_mtd_get_info(info);
+
+       info->sysfs_supported = 1;
+
+       /*
+        * We have to scan the MTD sysfs directory to identify how many MTD
+        * devices are present.
+        */
+       sysfs_mtd = opendir(lib->sysfs_mtd);
+       if (!sysfs_mtd) {
+               if (errno == ENOENT) {
+                       errno = ENODEV;
+                       return -1;
+               }
+               return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd);
+       }
+
+       info->lowest_mtd_num = INT_MAX;
+       while (1) {
+               int mtd_num, ret;
+               char tmp_buf[256];
+
+               errno = 0;
+               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;
+                       goto out_close;
+               }
+
+               ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s",
+                            &mtd_num, tmp_buf);
+               if (ret == 1) {
+                       info->mtd_dev_cnt += 1;
+                       if (mtd_num > info->highest_mtd_num)
+                               info->highest_mtd_num = mtd_num;
+                       if (mtd_num < info->lowest_mtd_num)
+                               info->lowest_mtd_num = mtd_num;
+               }
+       }
+
+       if (!dirent && errno) {
+               sys_errmsg("readdir failed on \"%s\"", lib->sysfs_mtd);
+               goto out_close;
+       }
+
+       if (closedir(sysfs_mtd))
+               return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd);
+
+       if (info->lowest_mtd_num == INT_MAX)
+               info->lowest_mtd_num = 0;
+
+       return 0;
+
+out_close:
+       closedir(sysfs_mtd);
+       return -1;
+}
+
+int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd)
+{
+       int ret;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       memset(mtd, 0, sizeof(struct mtd_dev_info));
+       mtd->mtd_num = mtd_num;
+
+       if (!mtd_dev_present(desc, mtd_num)) {
+               errno = ENODEV;
+               return -1;
+       } else if (!lib->sysfs_supported)
+               return legacy_get_dev_info1(mtd_num, mtd);
+
+       if (dev_get_major(lib, mtd_num, &mtd->major, &mtd->minor))
+               return -1;
+
+       ret = dev_read_data(lib->mtd_name, mtd_num, &mtd->name,
+                           MTD_NAME_MAX + 1);
+       if (ret < 0)
+               return -1;
+       ((char *)mtd->name)[ret - 1] = '\0';
+
+       ret = dev_read_data(lib->mtd_type, mtd_num, &mtd->type_str,
+                           MTD_TYPE_MAX + 1);
+       if (ret < 0)
+               return -1;
+       ((char *)mtd->type_str)[ret - 1] = '\0';
+
+       if (dev_read_pos_int(lib->mtd_eb_size, mtd_num, &mtd->eb_size))
+               return -1;
+       if (dev_read_pos_ll(lib->mtd_size, mtd_num, &mtd->size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_min_io_size, mtd_num, &mtd->min_io_size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_subpage_size, mtd_num, &mtd->subpage_size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_oob_size, mtd_num, &mtd->oob_size))
+               return -1;
+       if (dev_read_pos_int(lib->mtd_region_cnt, mtd_num, &mtd->region_cnt))
+               return -1;
+       if (dev_read_hex_int(lib->mtd_flags, mtd_num, &ret))
+               return -1;
+       mtd->writable = !!(ret & MTD_WRITEABLE);
+
+       mtd->eb_cnt = mtd->size / mtd->eb_size;
+       mtd->type = type_str2int(mtd->type_str);
+       mtd->bb_allowed = !!(mtd->type == MTD_NANDFLASH ||
+                               mtd->type == MTD_MLCNANDFLASH);
+
+       return 0;
+}
+
+int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd)
+{
+       int mtd_num;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       if (!lib->sysfs_supported)
+               return legacy_get_dev_info(node, mtd);
+
+       if (dev_node2num(lib, node, &mtd_num))
+               return -1;
+
+       return mtd_get_dev_info1(desc, mtd_num, mtd);
+}
+
+static inline int mtd_ioctl_error(const struct mtd_dev_info *mtd, int eb,
+                                 const char *sreq)
+{
+       return sys_errmsg("%s ioctl failed for eraseblock %d (mtd%d)",
+                         sreq, eb, mtd->mtd_num);
+}
+
+static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb)
+{
+       if (eb < 0 || eb >= mtd->eb_cnt) {
+               errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+                      eb, mtd->mtd_num, mtd->eb_cnt);
+               errno = EINVAL;
+               return -1;
+       }
+       return 0;
+}
+
+static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req,
+                    const char *sreq)
+{
+       int ret;
+       struct erase_info_user ei;
+
+       ret = mtd_valid_erase_block(mtd, eb);
+       if (ret)
+               return ret;
+
+       ei.start = eb * mtd->eb_size;
+       ei.length = mtd->eb_size;
+
+       ret = ioctl(fd, req, &ei);
+       if (ret < 0)
+               return mtd_ioctl_error(mtd, eb, sreq);
+
+       return 0;
+}
+#define mtd_xlock(mtd, fd, eb, req) mtd_xlock(mtd, fd, eb, req, #req)
+
+int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       return mtd_xlock(mtd, fd, eb, MEMLOCK);
+}
+
+int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       return mtd_xlock(mtd, fd, eb, MEMUNLOCK);
+}
+
+int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       int ret;
+       struct libmtd *lib = (struct libmtd *)desc;
+       struct erase_info_user64 ei64;
+       struct erase_info_user ei;
+
+       ret = mtd_valid_erase_block(mtd, eb);
+       if (ret)
+               return ret;
+
+       ei64.start = (__u64)eb * mtd->eb_size;
+       ei64.length = mtd->eb_size;
+
+       if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
+           lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
+               ret = ioctl(fd, MEMERASE64, &ei64);
+               if (ret == 0)
+                       return ret;
+
+               if (errno != ENOTTY ||
+                   lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN)
+                       return mtd_ioctl_error(mtd, eb, "MEMERASE64");
+
+               /*
+                * MEMERASE64 support was added in kernel version 2.6.31, so
+                * probably we are working with older kernel and this ioctl is
+                * not supported.
+                */
+               lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
+       }
+
+       if (ei64.start + ei64.length > 0xFFFFFFFF) {
+               errmsg("this system can address only %u eraseblocks",
+                      0xFFFFFFFFU / mtd->eb_size);
+               errno = EINVAL;
+               return -1;
+       }
+
+       ei.start = ei64.start;
+       ei.length = ei64.length;
+       ret = ioctl(fd, MEMERASE, &ei);
+       if (ret < 0)
+               return mtd_ioctl_error(mtd, eb, "MEMERASE");
+       return 0;
+}
+
+int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo)
+{
+       int ret;
+
+       if (regidx < 0) {
+               errno = ENODEV;
+               return -1;
+       }
+
+       reginfo->regionindex = regidx;
+
+       ret = ioctl(fd, MEMGETREGIONINFO, reginfo);
+       if (ret < 0)
+               return sys_errmsg("%s ioctl failed for erase region %d",
+                       "MEMGETREGIONINFO", regidx);
+
+       return 0;
+}
+
+int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       int ret;
+       erase_info_t ei;
+
+       ei.start = eb * mtd->eb_size;
+       ei.length = mtd->eb_size;
+
+       ret = ioctl(fd, MEMISLOCKED, &ei);
+       if (ret < 0) {
+               if (errno != ENOTTY && errno != EOPNOTSUPP)
+                       return mtd_ioctl_error(mtd, eb, "MEMISLOCKED");
+               else
+                       errno = EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
+/* Patterns to write to a physical eraseblock when torturing it */
+static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+
+/**
+ * check_pattern - check if buffer contains only a certain byte pattern.
+ * @buf: buffer to check
+ * @patt: the pattern to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %1 in there are only @patt bytes in @buf, and %0 if
+ * something else was also found.
+ */
+static int check_pattern(const void *buf, uint8_t patt, int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               if (((const uint8_t *)buf)[i] != patt)
+                       return 0;
+       return 1;
+}
+
+int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       int err, i, patt_count;
+       void *buf;
+
+       normsg("run torture test for PEB %d", eb);
+       patt_count = ARRAY_SIZE(patterns);
+
+       buf = xmalloc(mtd->eb_size);
+
+       for (i = 0; i < patt_count; i++) {
+               err = mtd_erase(desc, mtd, fd, eb);
+               if (err)
+                       goto out;
+
+               /* Make sure the PEB contains only 0xFF bytes */
+               err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+               if (err)
+                       goto out;
+
+               err = check_pattern(buf, 0xFF, mtd->eb_size);
+               if (err == 0) {
+                       errmsg("erased PEB %d, but a non-0xFF byte found", eb);
+                       errno = EIO;
+                       goto out;
+               }
+
+               /* Write a pattern and check it */
+               memset(buf, patterns[i], mtd->eb_size);
+               err = mtd_write(desc, mtd, fd, eb, 0, buf, mtd->eb_size, NULL,
+                               0, 0);
+               if (err)
+                       goto out;
+
+               memset(buf, ~patterns[i], mtd->eb_size);
+               err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+               if (err)
+                       goto out;
+
+               err = check_pattern(buf, patterns[i], mtd->eb_size);
+               if (err == 0) {
+                       errmsg("pattern %x checking failed for PEB %d",
+                               patterns[i], eb);
+                       errno = EIO;
+                       goto out;
+               }
+       }
+
+       err = 0;
+       normsg("PEB %d passed torture test, do not mark it a bad", eb);
+
+out:
+       free(buf);
+       return -1;
+}
+
+int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       int ret;
+       loff_t seek;
+
+       ret = mtd_valid_erase_block(mtd, eb);
+       if (ret)
+               return ret;
+
+       if (!mtd->bb_allowed)
+               return 0;
+
+       seek = (loff_t)eb * mtd->eb_size;
+       ret = ioctl(fd, MEMGETBADBLOCK, &seek);
+       if (ret == -1)
+               return mtd_ioctl_error(mtd, eb, "MEMGETBADBLOCK");
+       return ret;
+}
+
+int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+       int ret;
+       loff_t seek;
+
+       if (!mtd->bb_allowed) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       ret = mtd_valid_erase_block(mtd, eb);
+       if (ret)
+               return ret;
+
+       seek = (loff_t)eb * mtd->eb_size;
+       ret = ioctl(fd, MEMSETBADBLOCK, &seek);
+       if (ret == -1)
+               return mtd_ioctl_error(mtd, eb, "MEMSETBADBLOCK");
+       return 0;
+}
+
+int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+            void *buf, int len)
+{
+       int ret, rd = 0;
+       off_t seek;
+
+       ret = mtd_valid_erase_block(mtd, eb);
+       if (ret)
+               return ret;
+
+       if (offs < 0 || offs + len > mtd->eb_size) {
+               errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+                      offs, len, mtd->mtd_num, mtd->eb_size);
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* Seek to the beginning of the eraseblock */
+       seek = (off_t)eb * mtd->eb_size + offs;
+       if (lseek(fd, seek, SEEK_SET) != seek)
+               return sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t,
+                                 mtd->mtd_num, seek);
+
+       while (rd < len) {
+               ret = read(fd, buf, len);
+               if (ret < 0)
+                       return sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
+                                         len, mtd->mtd_num, eb, offs);
+               rd += ret;
+       }
+
+       return 0;
+}
+
+static int legacy_auto_oob_layout(const struct mtd_dev_info *mtd, int fd,
+                                 int ooblen, void *oob) {
+       struct nand_oobinfo old_oobinfo;
+       int start, len;
+       uint8_t *tmp_buf;
+
+       /* Read the current oob info */
+       if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo))
+               return sys_errmsg("MEMGETOOBSEL failed");
+
+       tmp_buf = malloc(ooblen);
+       memcpy(tmp_buf, oob, ooblen);
+
+       /*
+        * We use autoplacement and have the oobinfo with the autoplacement
+        * information from the kernel available
+        */
+       if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
+               int i, tags_pos = 0;
+               for (i = 0; old_oobinfo.oobfree[i][1]; i++) {
+                       /* Set the reserved bytes to 0xff */
+                       start = old_oobinfo.oobfree[i][0];
+                       len = old_oobinfo.oobfree[i][1];
+                       memcpy(oob + start, tmp_buf + tags_pos, len);
+                       tags_pos += len;
+               }
+       } else {
+               /* Set at least the ecc byte positions to 0xff */
+               start = old_oobinfo.eccbytes;
+               len = mtd->oob_size - start;
+               memcpy(oob + start, tmp_buf + start, len);
+       }
+
+       return 0;
+}
+
+int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
+             int offs, void *data, int len, void *oob, int ooblen,
+             uint8_t mode)
+{
+       int ret;
+       off_t seek;
+       struct mtd_write_req ops;
+
+       ret = mtd_valid_erase_block(mtd, eb);
+       if (ret)
+               return ret;
+
+       if (offs < 0 || offs + len > mtd->eb_size) {
+               errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+                      offs, len, mtd->mtd_num, mtd->eb_size);
+               errno = EINVAL;
+               return -1;
+       }
+       if (offs % mtd->subpage_size) {
+               errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
+                      offs, mtd->mtd_num, mtd->subpage_size);
+               errno = EINVAL;
+               return -1;
+       }
+       if (len % mtd->subpage_size) {
+               errmsg("write length %d is not aligned to mtd%d min. I/O size %d",
+                      len, mtd->mtd_num, mtd->subpage_size);
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* Calculate seek address */
+       seek = (off_t)eb * mtd->eb_size + offs;
+
+       if (oob) {
+               ops.start = seek;
+               ops.len = len;
+               ops.ooblen = ooblen;
+               ops.usr_data = (uint64_t)(unsigned long)data;
+               ops.usr_oob = (uint64_t)(unsigned long)oob;
+               ops.mode = mode;
+
+               ret = ioctl(fd, MEMWRITE, &ops);
+               if (ret == 0)
+                       return 0;
+               else if (errno != ENOTTY && errno != EOPNOTSUPP)
+                       return mtd_ioctl_error(mtd, eb, "MEMWRITE");
+
+               /* Fall back to old OOB ioctl() if necessary */
+               if (mode == MTD_OPS_AUTO_OOB)
+                       if (legacy_auto_oob_layout(mtd, fd, ooblen, oob))
+                               return -1;
+               if (mtd_write_oob(desc, mtd, fd, seek, ooblen, oob) < 0)
+                       return sys_errmsg("cannot write to OOB");
+       }
+       if (data) {
+               /* Seek to the beginning of the eraseblock */
+               if (lseek(fd, seek, SEEK_SET) != seek)
+                       return sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t,
+                                       mtd->mtd_num, seek);
+               ret = write(fd, data, len);
+               if (ret != len)
+                       return sys_errmsg("cannot write %d bytes to mtd%d "
+                                         "(eraseblock %d, offset %d)",
+                                         len, mtd->mtd_num, eb, offs);
+       }
+
+       return 0;
+}
+
+int do_oob_op(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+             uint64_t start, uint64_t length, void *data, unsigned int cmd64,
+             unsigned int cmd)
+{
+       int ret, oob_offs;
+       struct mtd_oob_buf64 oob64;
+       struct mtd_oob_buf oob;
+       unsigned long long max_offs;
+       const char *cmd64_str, *cmd_str;
+       struct libmtd *lib = (struct libmtd *)desc;
+
+       if (cmd64 ==  MEMREADOOB64) {
+               cmd64_str = "MEMREADOOB64";
+               cmd_str   = "MEMREADOOB";
+       } else {
+               cmd64_str = "MEMWRITEOOB64";
+               cmd_str   = "MEMWRITEOOB";
+       }
+
+       max_offs = (unsigned long long)mtd->eb_cnt * mtd->eb_size;
+       if (start >= max_offs) {
+               errmsg("bad page address %" PRIu64 ", mtd%d has %d eraseblocks (%llu bytes)",
+                      start, mtd->mtd_num, mtd->eb_cnt, max_offs);
+               errno = EINVAL;
+               return -1;
+       }
+
+       oob_offs = start & (mtd->min_io_size - 1);
+       if (oob_offs + length > mtd->oob_size || length == 0) {
+               errmsg("Cannot write %" PRIu64 " OOB bytes to address %" PRIu64 " (OOB offset %u) - mtd%d OOB size is only %d bytes",
+                      length, start, oob_offs, mtd->mtd_num,  mtd->oob_size);
+               errno = EINVAL;
+               return -1;
+       }
+
+       oob64.start = start;
+       oob64.length = length;
+       oob64.usr_ptr = (uint64_t)(unsigned long)data;
+
+       if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
+           lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
+               ret = ioctl(fd, cmd64, &oob64);
+               if (ret == 0)
+                       return ret;
+
+               if (errno != ENOTTY ||
+                   lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) {
+                       sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
+                                  cmd64_str, mtd->mtd_num, start, start / mtd->eb_size);
+               }
+
+               /*
+                * MEMREADOOB64/MEMWRITEOOB64 support was added in kernel
+                * version 2.6.31, so probably we are working with older kernel
+                * and these ioctls are not supported.
+                */
+               lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
+       }
+
+       if (oob64.start > 0xFFFFFFFFULL) {
+               errmsg("this system can address only up to address %lu",
+                      0xFFFFFFFFUL);
+               errno = EINVAL;
+               return -1;
+       }
+
+       oob.start = oob64.start;
+       oob.length = oob64.length;
+       oob.ptr = data;
+
+       ret = ioctl(fd, cmd, &oob);
+       if (ret < 0)
+               sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
+                          cmd_str, mtd->mtd_num, start, start / mtd->eb_size);
+       return ret;
+}
+
+int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+                uint64_t start, uint64_t length, void *data)
+{
+       return do_oob_op(desc, mtd, fd, start, length, data,
+                        MEMREADOOB64, MEMREADOOB);
+}
+
+int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+                 uint64_t start, uint64_t length, void *data)
+{
+       return do_oob_op(desc, mtd, fd, start, length, data,
+                        MEMWRITEOOB64, MEMWRITEOOB);
+}
+
+int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+                 const char *img_name)
+{
+       int tmp, ret, in_fd, len, written = 0;
+       off_t seek;
+       struct stat st;
+       char *buf;
+
+       ret = mtd_valid_erase_block(mtd, eb);
+       if (ret)
+               return ret;
+
+       if (offs < 0 || offs >= mtd->eb_size) {
+               errmsg("bad offset %d, mtd%d eraseblock size is %d",
+                      offs, mtd->mtd_num, mtd->eb_size);
+               errno = EINVAL;
+               return -1;
+       }
+       if (offs % mtd->subpage_size) {
+               errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
+                      offs, mtd->mtd_num, mtd->subpage_size);
+               errno = EINVAL;
+               return -1;
+       }
+
+       in_fd = open(img_name, O_RDONLY | O_CLOEXEC);
+       if (in_fd == -1)
+               return sys_errmsg("cannot open \"%s\"", img_name);
+
+       if (fstat(in_fd, &st)) {
+               sys_errmsg("cannot stat %s", img_name);
+               goto out_close;
+       }
+
+       len = st.st_size;
+       if (len % mtd->subpage_size) {
+               errmsg("size of \"%s\" is %d byte, which is not aligned to "
+                      "mtd%d min. I/O size %d", img_name, len, mtd->mtd_num,
+                      mtd->subpage_size);
+               errno = EINVAL;
+               goto out_close;
+       }
+       tmp = (offs + len + mtd->eb_size - 1) / mtd->eb_size;
+       if (eb + tmp > mtd->eb_cnt) {
+               errmsg("\"%s\" image size is %d bytes, mtd%d size is %d "
+                      "eraseblocks, the image does not fit if we write it "
+                      "starting from eraseblock %d, offset %d",
+                      img_name, len, mtd->mtd_num, mtd->eb_cnt, eb, offs);
+               errno = EINVAL;
+               goto out_close;
+       }
+
+       /* Seek to the beginning of the eraseblock */
+       seek = (off_t)eb * mtd->eb_size + offs;
+       if (lseek(fd, seek, SEEK_SET) != seek) {
+               sys_errmsg("cannot seek mtd%d to offset %"PRIdoff_t,
+                           mtd->mtd_num, seek);
+               goto out_close;
+       }
+
+       buf = xmalloc(mtd->eb_size);
+
+       while (written < len) {
+               int rd = 0;
+
+               do {
+                       ret = read(in_fd, buf, mtd->eb_size - offs - rd);
+                       if (ret == -1) {
+                               sys_errmsg("cannot read \"%s\"", img_name);
+                               goto out_free;
+                       }
+                       rd += ret;
+               } while (ret && rd < mtd->eb_size - offs);
+
+               ret = write(fd, buf, rd);
+               if (ret != rd) {
+                       sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)",
+                                  len, mtd->mtd_num, eb, offs);
+                       goto out_free;
+               }
+
+               offs = 0;
+               eb += 1;
+               written += rd;
+       }
+
+       free(buf);
+       close(in_fd);
+       return 0;
+
+out_free:
+       free(buf);
+out_close:
+       close(in_fd);
+       return -1;
+}
+
+int mtd_probe_node(libmtd_t desc, const char *node)
+{
+       struct stat st;
+       struct mtd_info info;
+       int i, mjr, mnr;
+       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;
+       }
+
+       mjr = major(st.st_rdev);
+       mnr = minor(st.st_rdev);
+
+       if (mtd_get_info((libmtd_t *)lib, &info))
+               return -1;
+
+       if (!lib->sysfs_supported)
+               return 0;
+
+       for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
+               int mjr1, mnr1, ret;
+
+               ret = dev_get_major(lib, i, &mjr1, &mnr1);
+               if (ret) {
+                       if (errno == ENOENT)
+                               continue;
+                       if (!errno)
+                               break;
+                       return -1;
+               }
+
+               if (mjr1 == mjr && mnr1 == mnr)
+                       return 1;
+       }
+
+       errno = 0;
+       return -1;
+}
diff --git a/oslib/libmtd.h b/oslib/libmtd.h
new file mode 100644 (file)
index 0000000..3625de5
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2008, 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+/* Imported from mtd-utils by dehrenberg */
+
+#ifndef __LIBMTD_H__
+#define __LIBMTD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Maximum MTD device name length */
+#define MTD_NAME_MAX 127
+/* Maximum MTD device type string length */
+#define MTD_TYPE_MAX 64
+
+/* MTD library descriptor */
+typedef void * libmtd_t;
+
+/* Forward decls */
+struct region_info_user;
+
+/**
+ * @mtd_dev_cnt: count of MTD devices in system
+ * @lowest_mtd_num: lowest MTD device number in system
+ * @highest_mtd_num: highest MTD device number in system
+ * @sysfs_supported: non-zero if sysfs is supported by MTD
+ */
+struct mtd_info
+{
+       int mtd_dev_cnt;
+       int lowest_mtd_num;
+       int highest_mtd_num;
+       unsigned int sysfs_supported:1;
+};
+
+/**
+ * struct mtd_dev_info - information about an MTD device.
+ * @mtd_num: MTD device number
+ * @major: major number of corresponding character device
+ * @minor: minor number of corresponding character device
+ * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
+ * @type_str: static R/O flash type string
+ * @name: device name
+ * @size: device size in bytes
+ * @eb_cnt: count of eraseblocks
+ * @eb_size: eraseblock size
+ * @min_io_size: minimum input/output unit size
+ * @subpage_size: sub-page size
+ * @oob_size: OOB size (zero if the device does not have OOB area)
+ * @region_cnt: count of additional erase regions
+ * @writable: zero if the device is read-only
+ * @bb_allowed: non-zero if the MTD device may have bad eraseblocks
+ */
+struct mtd_dev_info
+{
+       int mtd_num;
+       int major;
+       int minor;
+       int type;
+       char type_str[MTD_TYPE_MAX + 1];
+       char name[MTD_NAME_MAX + 1];
+       long long size;
+       int eb_cnt;
+       int eb_size;
+       int min_io_size;
+       int subpage_size;
+       int oob_size;
+       int region_cnt;
+       unsigned int writable:1;
+       unsigned int bb_allowed:1;
+};
+
+/**
+ * libmtd_open - open MTD library.
+ *
+ * This function initializes and opens the MTD library and returns MTD library
+ * descriptor in case of success and %NULL in case of failure. In case of
+ * failure, errno contains zero if MTD is not present in the system, or
+ * contains the error code if a real error happened.
+ */
+libmtd_t libmtd_open(void);
+
+/**
+ * libmtd_close - close MTD library.
+ * @desc: MTD library descriptor
+ */
+void libmtd_close(libmtd_t desc);
+
+/**
+ * mtd_dev_present - check whether a MTD device is present.
+ * @desc: MTD library descriptor
+ * @mtd_num: MTD device number to check
+ *
+ * This function returns %1 if MTD device is present and %0 if not.
+ */
+int mtd_dev_present(libmtd_t desc, int mtd_num);
+
+/**
+ * mtd_get_info - get general MTD information.
+ * @desc: MTD library descriptor
+ * @info: the MTD device information is returned here
+ *
+ * This function fills the passed @info object with general MTD information and
+ * returns %0 in case of success and %-1 in case of failure. If MTD subsystem is
+ * not present in the system, errno is set to @ENODEV.
+ */
+int mtd_get_info(libmtd_t desc, struct mtd_info *info);
+
+/**
+ * mtd_get_dev_info - get information about an MTD device.
+ * @desc: MTD library descriptor
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function gets information about MTD device defined by the @node device
+ * node file and saves this information in the @mtd object. Returns %0 in case
+ * of success and %-1 in case of failure. If MTD subsystem is not present in the
+ * system, or the MTD device does not exist, errno is set to @ENODEV.
+ */
+int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd);
+
+/**
+ * mtd_get_dev_info1 - get information about an MTD device.
+ * @desc: MTD library descriptor
+ * @mtd_num: MTD device number to fetch information about
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is identical to 'mtd_get_dev_info()' except that it accepts
+ * MTD device number, not MTD character device.
+ */
+int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd);
+
+/**
+ * mtd_lock - lock eraseblocks.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to lock
+ *
+ * This function locks eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_unlock - unlock eraseblocks.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to lock
+ *
+ * This function unlocks eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_erase - erase an eraseblock.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to erase
+ *
+ * This function erases eraseblock @eb of MTD device described by @fd. Returns
+ * %0 in case of success and %-1 in case of failure.
+ */
+int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_regioninfo - get information about an erase region.
+ * @fd: MTD device node file descriptor
+ * @regidx: index of region to look up
+ * @reginfo: the region information is returned here
+ *
+ * This function gets information about an erase region defined by the
+ * @regidx index and saves this information in the @reginfo object.
+ * Returns %0 in case of success and %-1 in case of failure. If the
+ * @regidx is not valid or unavailable, errno is set to @ENODEV.
+ */
+int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo);
+
+/**
+ * mtd_is_locked - see if the specified eraseblock is locked.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to check
+ *
+ * This function checks to see if eraseblock @eb of MTD device described
+ * by @fd is locked. Returns %0 if it is unlocked, %1 if it is locked, and
+ * %-1 in case of failure. If the ioctl is not supported (support was added in
+ * Linux kernel 2.6.36) or this particular device does not support it, errno is
+ * set to @ENOTSUPP.
+ */
+int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_torture - torture an eraseblock.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to torture
+ *
+ * This function tortures eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_is_bad - check if eraseblock is bad.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to check
+ *
+ * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
+ * and %-1 in case of failure.
+ */
+int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_mark_bad - mark an eraseblock as bad.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to mark as bad
+ *
+ * This function marks eraseblock @eb as bad. Returns %0 in case of success and
+ * %-1 in case of failure.
+ */
+int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_read - read data from an MTD device.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to read from
+ * @offs: offset withing the eraseblock to read from
+ * @buf: buffer to read data to
+ * @len: how many bytes to read
+ *
+ * This function reads @len bytes of data from eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd and stores the read data at buffer @buf.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+            void *buf, int len);
+
+/**
+ * mtd_write - write data to an MTD device.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to write to
+ * @offs: offset withing the eraseblock to write to
+ * @data: data buffer to write
+ * @len: how many data bytes to write
+ * @oob: OOB buffer to write
+ * @ooblen: how many OOB bytes to write
+ * @mode: write mode (e.g., %MTD_OOB_PLACE, %MTD_OOB_RAW)
+ *
+ * This function writes @len bytes of data to eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
+ * case of failure.
+ *
+ * Can only write to a single page at a time if writing to OOB.
+ */
+int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
+             int offs, void *data, int len, void *oob, int ooblen,
+             uint8_t mode);
+
+/**
+ * mtd_read_oob - read out-of-band area.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @start: page-aligned start address
+ * @length: number of OOB bytes to read
+ * @data: read buffer
+ *
+ * This function reads @length OOB bytes starting from address @start on
+ * MTD device described by @fd. The address is specified as page byte offset
+ * from the beginning of the MTD device. This function returns %0 in case of
+ * success and %-1 in case of failure.
+ */
+int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+                uint64_t start, uint64_t length, void *data);
+
+/**
+ * mtd_write_oob - write out-of-band area.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @start: page-aligned start address
+ * @length: number of OOB bytes to write
+ * @data: write buffer
+ *
+ * This function writes @length OOB bytes starting from address @start on
+ * MTD device described by @fd. The address is specified as page byte offset
+ * from the beginning of the MTD device. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+                 uint64_t start, uint64_t length, void *data);
+
+/**
+ * mtd_write_img - write a file to MTD device.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to write to
+ * @offs: offset withing the eraseblock to write to
+ * @img_name: the file to write
+ *
+ * This function writes an image @img_name the MTD device defined by @mtd. @eb
+ * and @offs are the starting eraseblock and offset on the MTD device. Returns
+ * %0 in case of success and %-1 in case of failure.
+ */
+int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+                 const char *img_name);
+
+/**
+ * mtd_probe_node - test MTD node.
+ * @desc: MTD library descriptor
+ * @node: the node to test
+ *
+ * This function tests whether @node is an MTD device node and returns %1 if it
+ * is, and %-1 if it is not (errno is %ENODEV in this case) or if an error
+ * occurred.
+ */
+int mtd_probe_node(libmtd_t desc, const char *node);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LIBMTD_H__ */
diff --git a/oslib/libmtd_common.h b/oslib/libmtd_common.h
new file mode 100644 (file)
index 0000000..a123323
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) Artem Bityutskiy, 2007, 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Imported from mtd-utils by dehrenberg */
+
+#ifndef __MTD_UTILS_COMMON_H__
+#define __MTD_UTILS_COMMON_H__
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <features.h>
+#include <inttypes.h>
+
+#ifndef PROGRAM_NAME
+# error "You must define PROGRAM_NAME before including this header"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MIN    /* some C lib headers define this for us */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#define min(a, b) MIN(a, b) /* glue for linux kernel source */
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+
+#define min_t(t,x,y) ({ \
+       typeof((x)) _x = (x); \
+       typeof((y)) _y = (y); \
+       (_x < _y) ? _x : _y; \
+})
+
+#define max_t(t,x,y) ({ \
+       typeof((x)) _x = (x); \
+       typeof((y)) _y = (y); \
+       (_x > _y) ? _x : _y; \
+})
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+/* define a print format specifier for off_t */
+#ifdef __USE_FILE_OFFSET64
+#define PRIxoff_t PRIx64
+#define PRIdoff_t PRId64
+#else
+#define PRIxoff_t "l"PRIx32
+#define PRIdoff_t "l"PRId32
+#endif
+
+/* Verbose messages */
+#define bareverbose(verbose, fmt, ...) do {                        \
+       if (verbose)                                               \
+               printf(fmt, ##__VA_ARGS__);                        \
+} while(0)
+#define verbose(verbose, fmt, ...) \
+       bareverbose(verbose, "%s: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__)
+
+/* Normal messages */
+#define normsg_cont(fmt, ...) do {                                 \
+       printf("%s: " fmt, PROGRAM_NAME, ##__VA_ARGS__);           \
+} while(0)
+#define normsg(fmt, ...) do {                                      \
+       normsg_cont(fmt "\n", ##__VA_ARGS__);                      \
+} while(0)
+
+/* Error messages */
+#define errmsg(fmt, ...)  ({                                                \
+       fprintf(stderr, "%s: error!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
+       -1;                                                                 \
+})
+#define errmsg_die(fmt, ...) do {                                           \
+       exit(errmsg(fmt, ##__VA_ARGS__));                                   \
+} while(0)
+
+/* System error messages */
+#define sys_errmsg(fmt, ...)  ({                                            \
+       int _err = errno;                                                   \
+       errmsg(fmt, ##__VA_ARGS__);                                         \
+       fprintf(stderr, "%*serror %d (%s)\n", (int)sizeof(PROGRAM_NAME) + 1,\
+               "", _err, strerror(_err));                                  \
+       -1;                                                                 \
+})
+#define sys_errmsg_die(fmt, ...) do {                                       \
+       exit(sys_errmsg(fmt, ##__VA_ARGS__));                               \
+} while(0)
+
+/* Warnings */
+#define warnmsg(fmt, ...) do {                                                \
+       fprintf(stderr, "%s: warning!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
+} while(0)
+
+#if defined(__UCLIBC__)
+/* uClibc versions before 0.9.34 don't have rpmatch() */
+#if __UCLIBC_MAJOR__ == 0 && \
+               (__UCLIBC_MINOR__ < 9 || \
+               (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 34))
+#undef rpmatch
+#define rpmatch __rpmatch
+static inline int __rpmatch(const char *resp)
+{
+    return (resp[0] == 'y' || resp[0] == 'Y') ? 1 :
+       (resp[0] == 'n' || resp[0] == 'N') ? 0 : -1;
+}
+#endif
+#endif
+
+/**
+ * prompt the user for confirmation
+ */
+static inline bool prompt(const char *msg, bool def)
+{
+       char *line = NULL;
+       size_t len;
+       bool ret = def;
+
+       do {
+               normsg_cont("%s (%c/%c) ", msg, def ? 'Y' : 'y', def ? 'n' : 'N');
+               fflush(stdout);
+
+               while (getline(&line, &len, stdin) == -1) {
+                       printf("failed to read prompt; assuming '%s'\n",
+                               def ? "yes" : "no");
+                       break;
+               }
+
+               if (strcmp("\n", line) != 0) {
+                       switch (rpmatch(line)) {
+                       case 0: ret = false; break;
+                       case 1: ret = true; break;
+                       case -1:
+                               puts("unknown response; please try again");
+                               continue;
+                       }
+               }
+               break;
+       } while (1);
+
+       free(line);
+
+       return ret;
+}
+
+static inline int is_power_of_2(unsigned long long n)
+{
+       return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+/**
+ * simple_strtoX - convert a hex/dec/oct string into a number
+ * @snum: buffer to convert
+ * @error: set to 1 when buffer isn't fully consumed
+ *
+ * These functions are similar to the standard strtoX() functions, but they are
+ * a little bit easier to use if you want to convert full string of digits into
+ * the binary form. The typical usage:
+ *
+ * int error = 0;
+ * unsigned long num;
+ *
+ * num = simple_strtoul(str, &error);
+ * if (error || ... if needed, your check that num is not out of range ...)
+ *     error_happened();
+ */
+#define simple_strtoX(func, type) \
+static inline type simple_##func(const char *snum, int *error) \
+{ \
+       char *endptr; \
+       type ret = func(snum, &endptr, 0); \
+ \
+       if (error && (!*snum || *endptr)) { \
+               errmsg("%s: unable to parse the number '%s'", #func, snum); \
+               *error = 1; \
+       } \
+ \
+       return ret; \
+}
+simple_strtoX(strtol, long int)
+simple_strtoX(strtoll, long long int)
+simple_strtoX(strtoul, unsigned long int)
+simple_strtoX(strtoull, unsigned long long int)
+
+/* Simple version-printing for utils */
+#define common_print_version() \
+do { \
+       printf("%s %s\n", PROGRAM_NAME, VERSION); \
+} while (0)
+
+#include "libmtd_xalloc.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__MTD_UTILS_COMMON_H__ */
diff --git a/oslib/libmtd_int.h b/oslib/libmtd_int.h
new file mode 100644 (file)
index 0000000..cbe2ff5
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+/* Imported from mtd-utils by dehrenberg */
+
+#ifndef __LIBMTD_INT_H__
+#define __LIBMTD_INT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PROGRAM_NAME "libmtd"
+
+#define SYSFS_MTD        "class/mtd"
+#define MTD_NAME_PATT    "mtd%d"
+#define MTD_DEV          "dev"
+#define MTD_NAME         "name"
+#define MTD_TYPE         "type"
+#define MTD_EB_SIZE      "erasesize"
+#define MTD_SIZE         "size"
+#define MTD_MIN_IO_SIZE  "writesize"
+#define MTD_SUBPAGE_SIZE "subpagesize"
+#define MTD_OOB_SIZE     "oobsize"
+#define MTD_REGION_CNT   "numeraseregions"
+#define MTD_FLAGS        "flags"
+
+#define OFFS64_IOCTLS_UNKNOWN       0
+#define OFFS64_IOCTLS_NOT_SUPPORTED 1
+#define OFFS64_IOCTLS_SUPPORTED     2
+
+/**
+ * libmtd - MTD library description data structure.
+ * @sysfs_mtd: MTD directory in sysfs
+ * @mtd: MTD device sysfs directory pattern
+ * @mtd_dev: MTD device major/minor numbers file pattern
+ * @mtd_name: MTD device name file pattern
+ * @mtd_type: MTD device type file pattern
+ * @mtd_eb_size: MTD device eraseblock size file pattern
+ * @mtd_size: MTD device size file pattern
+ * @mtd_min_io_size: minimum I/O unit size file pattern
+ * @mtd_subpage_size: sub-page size file pattern
+ * @mtd_oob_size: MTD device OOB size file pattern
+ * @mtd_region_cnt: count of additional erase regions file pattern
+ * @mtd_flags: MTD device flags file pattern
+ * @sysfs_supported: non-zero if sysfs is supported by MTD
+ * @offs64_ioctls: %OFFS64_IOCTLS_SUPPORTED if 64-bit %MEMERASE64,
+ *                 %MEMREADOOB64, %MEMWRITEOOB64 MTD device ioctls are
+ *                 supported, %OFFS64_IOCTLS_NOT_SUPPORTED if not, and
+ *                 %OFFS64_IOCTLS_UNKNOWN if it is not known yet;
+ *
+ *  Note, we cannot find out whether 64-bit ioctls are supported by MTD when we
+ *  are initializing the library, because this requires an MTD device node.
+ *  Indeed, we have to actually call the ioctl and check for %ENOTTY to find
+ *  out whether it is supported or not.
+ *
+ *  Thus, we leave %offs64_ioctls uninitialized in 'libmtd_open()', and
+ *  initialize it later, when corresponding libmtd function is used, and when
+ *  we actually have a device node and can invoke an ioctl command on it.
+ */
+struct libmtd
+{
+       char *sysfs_mtd;
+       char *mtd;
+       char *mtd_dev;
+       char *mtd_name;
+       char *mtd_type;
+       char *mtd_eb_size;
+       char *mtd_size;
+       char *mtd_min_io_size;
+       char *mtd_subpage_size;
+       char *mtd_oob_size;
+       char *mtd_region_cnt;
+       char *mtd_flags;
+       unsigned int sysfs_supported:1;
+       unsigned int offs64_ioctls:2;
+};
+
+int legacy_libmtd_open(void);
+int legacy_dev_present(int mtd_num);
+int legacy_mtd_get_info(struct mtd_info *info);
+int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd);
+int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBMTD_INT_H__ */
diff --git a/oslib/libmtd_legacy.c b/oslib/libmtd_legacy.c
new file mode 100644 (file)
index 0000000..38dc2b7
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * This file  is part of the MTD library. Implements pre-2.6.30 kernels support,
+ * where MTD did not have sysfs interface. The main limitation of the old
+ * kernels was that the sub-page size was not exported to user-space, so it was
+ * not possible to get sub-page size.
+ */
+
+/* Imported from mtd-utils by dehrenberg */
+
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include "libmtd.h"
+#include "libmtd_int.h"
+#include "libmtd_common.h"
+
+#define MTD_PROC_FILE "/proc/mtd"
+#define MTD_DEV_PATT  "/dev/mtd%d"
+#define MTD_DEV_MAJOR 90
+
+#define PROC_MTD_FIRST     "dev:    size   erasesize  name\n"
+#define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1)
+#define PROC_MTD_MAX_LEN   4096
+#define PROC_MTD_PATT      "mtd%d: %llx %x"
+
+/**
+ * struct proc_parse_info - /proc/mtd parsing information.
+ * @mtd_num: MTD device number
+ * @size: device size
+ * @eb_size: eraseblock size
+ * @name: device name
+ * @buf: contents of /proc/mtd
+ * @data_size: how much data was read into @buf
+ * @pos: next string in @buf to parse
+ */
+struct proc_parse_info
+{
+       int mtd_num;
+       long long size;
+       char name[MTD_NAME_MAX + 1];
+       int eb_size;
+       char *buf;
+       int data_size;
+       char *next;
+};
+
+static int proc_parse_start(struct proc_parse_info *pi)
+{
+       int fd, ret;
+
+       fd = open(MTD_PROC_FILE, O_RDONLY);
+       if (fd == -1)
+               return -1;
+
+       pi->buf = xmalloc(PROC_MTD_MAX_LEN);
+
+       ret = read(fd, pi->buf, PROC_MTD_MAX_LEN);
+       if (ret == -1) {
+               sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
+               goto out_free;
+       }
+
+       if (ret < PROC_MTD_FIRST_LEN ||
+           memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) {
+               errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE,
+                      PROC_MTD_FIRST);
+               goto out_free;
+       }
+
+       pi->data_size = ret;
+       pi->next = pi->buf + PROC_MTD_FIRST_LEN;
+
+       close(fd);
+       return 0;
+
+out_free:
+       free(pi->buf);
+       close(fd);
+       return -1;
+}
+
+static int proc_parse_next(struct proc_parse_info *pi)
+{
+       int ret, len, pos = pi->next - pi->buf;
+       char *p, *p1;
+
+       if (pos >= pi->data_size) {
+               free(pi->buf);
+               return 0;
+       }
+
+       ret = sscanf(pi->next, PROC_MTD_PATT, &pi->mtd_num, &pi->size,
+                    &pi->eb_size);
+       if (ret != 3)
+               return errmsg("\"%s\" pattern not found", PROC_MTD_PATT);
+
+       p = memchr(pi->next, '\"', pi->data_size - pos);
+       if (!p)
+               return errmsg("opening \" not found");
+       p += 1;
+       pos = p - pi->buf;
+       if (pos >= pi->data_size)
+               return errmsg("opening \" not found");
+
+       p1 = memchr(p, '\"', pi->data_size - pos);
+       if (!p1)
+               return errmsg("closing \" not found");
+       pos = p1 - pi->buf;
+       if (pos >= pi->data_size)
+               return errmsg("closing \" not found");
+
+       len = p1 - p;
+       if (len > MTD_NAME_MAX)
+               return errmsg("too long mtd%d device name", pi->mtd_num);
+
+       memcpy(pi->name, p, len);
+       pi->name[len] = '\0';
+
+       if (p1[1] != '\n')
+               return errmsg("opening \"\n\" not found");
+       pi->next = p1 + 2;
+       return 1;
+}
+
+/**
+ * legacy_libmtd_open - legacy version of 'libmtd_open()'.
+ *
+ * This function is just checks that MTD is present in the system. Returns
+ * zero in case of success and %-1 in case of failure. In case of failure,
+ * errno contains zero if MTD is not present in the system, or contains the
+ * error code if a real error happened. This is similar to the 'libmtd_open()'
+ * return conventions.
+ */
+int legacy_libmtd_open(void)
+{
+       int fd;
+
+       fd = open(MTD_PROC_FILE, O_RDONLY);
+       if (fd == -1) {
+               if (errno == ENOENT)
+                       errno = 0;
+               return -1;
+       }
+
+       close(fd);
+       return 0;
+}
+
+/**
+ * legacy_dev_presentl - legacy version of 'mtd_dev_present()'.
+ * @info: the MTD device information is returned here
+ *
+ * When the kernel does not provide sysfs files for the MTD subsystem,
+ * fall-back to parsing the /proc/mtd file to determine whether an mtd device
+ * number @mtd_num is present.
+ */
+int legacy_dev_present(int mtd_num)
+{
+       int ret;
+       struct proc_parse_info pi;
+
+       ret = proc_parse_start(&pi);
+       if (ret)
+               return -1;
+
+       while (proc_parse_next(&pi)) {
+               if (pi.mtd_num == mtd_num)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * legacy_mtd_get_info - legacy version of 'mtd_get_info()'.
+ * @info: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_info()' and has the same conventions.
+ */
+int legacy_mtd_get_info(struct mtd_info *info)
+{
+       int ret;
+       struct proc_parse_info pi;
+
+       ret = proc_parse_start(&pi);
+       if (ret)
+               return -1;
+
+       info->lowest_mtd_num = INT_MAX;
+       while (proc_parse_next(&pi)) {
+               info->mtd_dev_cnt += 1;
+               if (pi.mtd_num > info->highest_mtd_num)
+                       info->highest_mtd_num = pi.mtd_num;
+               if (pi.mtd_num < info->lowest_mtd_num)
+                       info->lowest_mtd_num = pi.mtd_num;
+       }
+
+       return 0;
+}
+
+/**
+ * legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'.
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_dev_info()' and has the same
+ * conventions.
+ */
+int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd)
+{
+       struct stat st;
+       struct mtd_info_user ui;
+       int fd, ret;
+       loff_t offs = 0;
+       struct proc_parse_info pi;
+
+       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;
+               return errmsg("\"%s\" is not a character device", node);
+       }
+
+       memset(mtd, '\0', sizeof(struct mtd_dev_info));
+       mtd->major = major(st.st_rdev);
+       mtd->minor = minor(st.st_rdev);
+
+       if (mtd->major != MTD_DEV_MAJOR) {
+               errno = EINVAL;
+               return errmsg("\"%s\" has major number %d, MTD devices have "
+                             "major %d", node, mtd->major, MTD_DEV_MAJOR);
+       }
+
+       mtd->mtd_num = mtd->minor / 2;
+
+       fd = open(node, O_RDONLY);
+       if (fd == -1)
+               return sys_errmsg("cannot open \"%s\"", node);
+
+       if (ioctl(fd, MEMGETINFO, &ui)) {
+               sys_errmsg("MEMGETINFO ioctl request failed");
+               goto out_close;
+       }
+
+       ret = ioctl(fd, MEMGETBADBLOCK, &offs);
+       if (ret == -1) {
+               if (errno != EOPNOTSUPP) {
+                       sys_errmsg("MEMGETBADBLOCK ioctl failed");
+                       goto out_close;
+               }
+               errno = 0;
+               mtd->bb_allowed = 0;
+       } else
+               mtd->bb_allowed = 1;
+
+       mtd->type = ui.type;
+       mtd->size = ui.size;
+       mtd->eb_size = ui.erasesize;
+       mtd->min_io_size = ui.writesize;
+       mtd->oob_size = ui.oobsize;
+
+       if (mtd->min_io_size <= 0) {
+               errmsg("mtd%d (%s) has insane min. I/O unit size %d",
+                      mtd->mtd_num, node, mtd->min_io_size);
+               goto out_close;
+       }
+       if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
+               errmsg("mtd%d (%s) has insane eraseblock size %d",
+                      mtd->mtd_num, node, mtd->eb_size);
+               goto out_close;
+       }
+       if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
+               errmsg("mtd%d (%s) has insane size %lld",
+                      mtd->mtd_num, node, mtd->size);
+               goto out_close;
+       }
+       mtd->eb_cnt = mtd->size / mtd->eb_size;
+
+       switch(mtd->type) {
+       case MTD_ABSENT:
+               errmsg("mtd%d (%s) is removable and is not present",
+                      mtd->mtd_num, node);
+               goto out_close;
+       case MTD_RAM:
+               strcpy((char *)mtd->type_str, "ram");
+               break;
+       case MTD_ROM:
+               strcpy((char *)mtd->type_str, "rom");
+               break;
+       case MTD_NORFLASH:
+               strcpy((char *)mtd->type_str, "nor");
+               break;
+       case MTD_NANDFLASH:
+               strcpy((char *)mtd->type_str, "nand");
+               break;
+       case MTD_MLCNANDFLASH:
+               strcpy((char *)mtd->type_str, "mlc-nand");
+               break;
+       case MTD_DATAFLASH:
+               strcpy((char *)mtd->type_str, "dataflash");
+               break;
+       case MTD_UBIVOLUME:
+               strcpy((char *)mtd->type_str, "ubi");
+               break;
+       default:
+               goto out_close;
+       }
+
+       if (ui.flags & MTD_WRITEABLE)
+               mtd->writable = 1;
+       mtd->subpage_size = mtd->min_io_size;
+
+       close(fd);
+
+       /*
+        * Unfortunately, the device name is not available via ioctl, and
+        * we have to parse /proc/mtd to get it.
+        */
+       ret = proc_parse_start(&pi);
+       if (ret)
+               return -1;
+
+       while (proc_parse_next(&pi)) {
+               if (pi.mtd_num == mtd->mtd_num) {
+                       strcpy((char *)mtd->name, pi.name);
+                       return 0;
+               }
+       }
+
+       errmsg("mtd%d not found in \"%s\"", mtd->mtd_num, MTD_PROC_FILE);
+       errno = ENOENT;
+       return -1;
+
+out_close:
+       close(fd);
+       return -1;
+}
+
+/**
+ * legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'.
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_dev_info1()' and has the same
+ * conventions.
+ */
+int legacy_get_dev_info1(int mtd_num, struct mtd_dev_info *mtd)
+{
+       char node[sizeof(MTD_DEV_PATT) + 20];
+
+       sprintf(node, MTD_DEV_PATT, mtd_num);
+       return legacy_get_dev_info(node, mtd);
+}
diff --git a/oslib/libmtd_xalloc.h b/oslib/libmtd_xalloc.h
new file mode 100644 (file)
index 0000000..532b80f
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * memory wrappers
+ *
+ * Copyright (c) Artem Bityutskiy, 2007, 2008
+ * Copyright 2001, 2002 Red Hat, Inc.
+ *           2001 David A. Schleef <ds@lineo.com>
+ *           2002 Axis Communications AB
+ *           2001, 2002 Erik Andersen <andersen@codepoet.org>
+ *           2004 University of Szeged, Hungary
+ *           2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MTD_UTILS_XALLOC_H__
+#define __MTD_UTILS_XALLOC_H__
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Mark these functions as unused so that gcc does not emit warnings
+ * when people include this header but don't use every function.
+ */
+
+__attribute__((unused))
+static void *xmalloc(size_t size)
+{
+       void *ptr = malloc(size);
+
+       if (ptr == NULL && size != 0)
+               sys_errmsg_die("out of memory");
+       return ptr;
+}
+
+__attribute__((unused))
+static void *xcalloc(size_t nmemb, size_t size)
+{
+       void *ptr = calloc(nmemb, size);
+
+       if (ptr == NULL && nmemb != 0 && size != 0)
+               sys_errmsg_die("out of memory");
+       return ptr;
+}
+
+__attribute__((unused))
+static void *xzalloc(size_t size)
+{
+       return xcalloc(1, size);
+}
+
+__attribute__((unused))
+static void *xrealloc(void *ptr, size_t size)
+{
+       ptr = realloc(ptr, size);
+       if (ptr == NULL && size != 0)
+               sys_errmsg_die("out of memory");
+       return ptr;
+}
+
+__attribute__((unused))
+static char *xstrdup(const char *s)
+{
+       char *t;
+
+       if (s == NULL)
+               return NULL;
+       t = strdup(s);
+       if (t == NULL)
+               sys_errmsg_die("out of memory");
+       return t;
+}
+
+#ifdef _GNU_SOURCE
+
+__attribute__((unused))
+static int xasprintf(char **strp, const char *fmt, ...)
+{
+       int cnt;
+       va_list ap;
+
+       va_start(ap, fmt);
+       cnt = vasprintf(strp, fmt, ap);
+       va_end(ap);
+
+       if (cnt == -1)
+               sys_errmsg_die("out of memory");
+
+       return cnt;
+}
+#endif
+
+#endif /* !__MTD_UTILS_XALLOC_H__ */
diff --git a/oslib/linux-dev-lookup.c b/oslib/linux-dev-lookup.c
new file mode 100644 (file)
index 0000000..4d5f356
--- /dev/null
@@ -0,0 +1,66 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "../os/os.h"
+
+int blktrace_lookup_device(const char *redirect, char *path, unsigned int maj,
+                          unsigned int min)
+{
+       struct dirent *dir;
+       struct stat st;
+       int found = 0;
+       DIR *D;
+
+       D = opendir(path);
+       if (!D)
+               return 0;
+
+       while ((dir = readdir(D)) != NULL) {
+               char full_path[256];
+
+               if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
+                       continue;
+
+               sprintf(full_path, "%s%s%s", path, FIO_OS_PATH_SEPARATOR, dir->d_name);
+               if (lstat(full_path, &st) == -1) {
+                       perror("lstat");
+                       break;
+               }
+
+               if (S_ISDIR(st.st_mode)) {
+                       found = blktrace_lookup_device(redirect, full_path,
+                                                               maj, min);
+                       if (found) {
+                               strcpy(path, full_path);
+                               break;
+                       }
+               }
+
+               if (!S_ISBLK(st.st_mode))
+                       continue;
+
+               /*
+                * If replay_redirect is set then always return this device
+                * upon lookup which overrides the device lookup based on
+                * major minor in the actual blktrace
+                */
+               if (redirect) {
+                       strcpy(path, redirect);
+                       found = 1;
+                       break;
+               }
+
+               if (maj == major(st.st_rdev) && min == minor(st.st_rdev)) {
+                       strcpy(path, full_path);
+                       found = 1;
+                       break;
+               }
+       }
+
+       closedir(D);
+       return found;
+}
diff --git a/oslib/linux-dev-lookup.h b/oslib/linux-dev-lookup.h
new file mode 100644 (file)
index 0000000..144f33a
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef LINUX_DEV_LOOKUP
+#define LINUX_DEV_LOOKUP
+
+int blktrace_lookup_device(const char *redirect, char *path, unsigned int maj,
+                          unsigned int min);
+
+#endif
diff --git a/oslib/strcasestr.c b/oslib/strcasestr.c
new file mode 100644 (file)
index 0000000..92cf24c
--- /dev/null
@@ -0,0 +1,25 @@
+#include <ctype.h>
+#include <stddef.h>
+
+char *strcasestr(const char *s1, const char *s2)
+{
+       const char *s = s1;
+       const char *p = s2;
+
+       do {
+               if (!*p)
+                       return (char *) s1;
+               if ((*p == *s) ||
+                   (tolower(*p) == tolower(*s))) {
+                       ++p;
+                       ++s;
+               } else {
+                       p = s2;
+                       if (!*s)
+                               return NULL;
+                       s = ++s1;
+               }
+       } while (1);
+
+       return *p ? NULL : (char *) s1;
+}
diff --git a/oslib/strcasestr.h b/oslib/strcasestr.h
new file mode 100644 (file)
index 0000000..43d61df
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef CONFIG_STRCASESTR
+
+#include <string.h>
+
+#else
+
+#ifndef FIO_STRCASESTR_H
+#define FIO_STRCASESTR_H
+
+char *strcasestr(const char *haystack, const char *needle);
+
+#endif
+#endif
diff --git a/oslib/strlcat.c b/oslib/strlcat.c
new file mode 100644 (file)
index 0000000..643d496
--- /dev/null
@@ -0,0 +1,23 @@
+#include <string.h>
+
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+       size_t dstlen;
+       size_t srclen;
+
+       dstlen = strlen(dst);
+       size -= dstlen + 1;
+
+       /* return if no room */
+       if (!size)
+               return dstlen;
+
+       srclen = strlen(src);
+       if (srclen > size)
+               srclen = size;
+
+       memcpy(dst + dstlen, src, srclen);
+       dst[dstlen + srclen] = '\0';
+
+       return dstlen + srclen;
+}
diff --git a/oslib/strlcat.h b/oslib/strlcat.h
new file mode 100644 (file)
index 0000000..baeace4
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef FIO_STRLCAT_H
+#define FIO_STRLCAT_H
+
+size_t strlcat(char *dst, const char *src, size_t size);
+
+#endif
diff --git a/oslib/strsep.c b/oslib/strsep.c
new file mode 100644 (file)
index 0000000..b71e9f7
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdio.h>
+
+char *strsep(char **stringp, const char *delim)
+{
+       char *s, *tok;
+       const char *spanp;
+       int c, sc;
+
+       s = *stringp;
+       if (!s)
+               return NULL;
+
+       tok = s;
+       do {
+               c = *s++;
+               spanp = delim;
+               do {
+                       sc = *spanp++;
+                       if (sc == c) {
+                               if (c == 0)
+                                       s = NULL;
+                               else
+                                       s[-1] = 0;
+                               *stringp = s;
+                               return tok;
+                       }
+               } while (sc != 0);
+       } while (1);
+}
diff --git a/oslib/strsep.h b/oslib/strsep.h
new file mode 100644 (file)
index 0000000..5fea5d1
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef FIO_STRSEP_LIB_H
+#define FIO_STRSEP_LIB_H
+
+char *strsep(char **, const char *);
+
+#endif
index 04b6abedb8428fda2c0712f627a5749d1fd85185..c589ceaf2465aa6461dd2e6285d8a7870c2a6a73 100644 (file)
@@ -12,7 +12,7 @@
 #include "../blktrace_api.h"
 #include "../os/os.h"
 #include "../log.h"
 #include "../blktrace_api.h"
 #include "../os/os.h"
 #include "../log.h"
-#include "../lib/linux-dev-lookup.h"
+#include "../oslib/linux-dev-lookup.h"
 
 #define TRACE_FIFO_SIZE        8192
 
 
 #define TRACE_FIFO_SIZE        8192