summaryrefslogtreecommitdiff
path: root/package/system/fstools
diff options
context:
space:
mode:
authorLudovic Pouzenc <ludovic@pouzenc.fr>2018-09-16 19:26:25 +0200
committerLudovic Pouzenc <ludovic@pouzenc.fr>2018-09-16 19:26:25 +0200
commit4dc1eee385f1b5115976db8d6b60ca0a08ed05ce (patch)
tree8c2562a28e69949dee07563a8bedc6029d7acc9a /package/system/fstools
parentbe049529e6a883601fd47303a05165a6a0b9a4a5 (diff)
downloadmtk-20170518-4dc1eee385f1b5115976db8d6b60ca0a08ed05ce.zip
mtk-20170518-4dc1eee385f1b5115976db8d6b60ca0a08ed05ce.tar.gz
mtk-20170518-4dc1eee385f1b5115976db8d6b60ca0a08ed05ce.tar.bz2
package/system: probably from OpenWRT
Diffstat (limited to 'package/system/fstools')
-rw-r--r--package/system/fstools/Makefile23
-rw-r--r--package/system/fstools/files/fstab.default2
-rw-r--r--package/system/fstools/files/samba.hotplug47
-rw-r--r--package/system/fstools/patches/001-usb-auto-mount.patch227
-rw-r--r--package/system/fstools/patches/002-ntfs-exfat.patch525
-rw-r--r--package/system/fstools/patches/003-nand-jffs2.patch13
-rw-r--r--package/system/fstools/patches/004-emmc.patch597
-rw-r--r--package/system/fstools/patches/005-mount-options.patch102
-rw-r--r--package/system/fstools/patches/006-7623-nand.patch819
9 files changed, 2351 insertions, 4 deletions
diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile
index 18098dd..7e93ec9 100644
--- a/package/system/fstools/Makefile
+++ b/package/system/fstools/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2014 OpenWrt.org
+# Copyright (C) 2014-2015 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
@@ -8,14 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fstools
-PKG_VERSION:=2014-06-22
+PKG_VERSION:=2015-02-25.1
PKG_RELEASE=$(PKG_SOURCE_VERSION)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=git://nbd.name/fstools.git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
-PKG_SOURCE_VERSION:=e0430f5c62f367e5a8e02755412977b02c3fc45e
+PKG_SOURCE_VERSION:=914b023e71559e033ec5a1f9840511eb1ccaf386
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
CMAKE_INSTALL:=1
PKG_CHECK_FORMAT_SECURITY:=0
@@ -23,18 +23,32 @@ PKG_CHECK_FORMAT_SECURITY:=0
PKG_LICENSE:=GPLv2
PKG_LICENSE_FILES:=
+PKG_USE_MIPS16:=0
+
PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
TARGET_LDFLAGS += $(if $(CONFIG_USE_EGLIBC),-lrt)
+CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_UBIFS_EXTROOT),-DCMAKE_UBIFS_EXTROOT=y)
define Package/fstools
SECTION:=base
CATEGORY:=Base system
DEPENDS:=+ubox +USE_EGLIBC:librt +NAND_SUPPORT:ubi-utils
TITLE:=OpenWrt filesystem tools
+ MENU:=1
+endef
+
+define Package/fstools/config
+ config FSTOOLS_UBIFS_EXTROOT
+ depends on PACKAGE_fstools
+ depends on NAND_SUPPORT
+ bool "Support extroot functionality with UBIFS"
+ default y
+ help
+ This option makes it possible to use extroot functionality if the root filesystem resides on an UBIFS partition
endef
define Package/block-mount
@@ -47,7 +61,7 @@ endef
define Package/fstools/install
$(INSTALL_DIR) $(1)/sbin $(1)/lib
- $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{mount_root,jffs2reset,snapshot_tool} $(1)/sbin/
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{mount_root,mount_root2,jffs2reset,snapshot_tool} $(1)/sbin/
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libfstools.so $(1)/lib/
$(INSTALL_BIN) ./files/snapshot $(1)/sbin/
ln -s /sbin/jffs2reset $(1)/sbin/jffs2mark
@@ -59,6 +73,7 @@ define Package/block-mount/install
$(INSTALL_BIN) ./files/fstab.init $(1)/etc/init.d/fstab
$(INSTALL_DATA) ./files/fstab.default $(1)/etc/uci-defaults/10-fstab
$(INSTALL_DATA) ./files/mount.hotplug $(1)/etc/hotplug.d/block/10-mount
+ -$(INSTALL_DATA) ./files/samba.hotplug $(1)/etc/hotplug.d/block/11-samba
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/block $(1)/sbin/
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libblkid-tiny.so $(1)/lib/
diff --git a/package/system/fstools/files/fstab.default b/package/system/fstools/files/fstab.default
index dd4ba1c..f794bb9 100644
--- a/package/system/fstools/files/fstab.default
+++ b/package/system/fstools/files/fstab.default
@@ -1 +1,3 @@
+touch /tmp/fstab
[ ! -f /etc/config/fstab ] && ( block detect > /etc/config/fstab )
+exit 0
diff --git a/package/system/fstools/files/samba.hotplug b/package/system/fstools/files/samba.hotplug
new file mode 100644
index 0000000..270e32c
--- /dev/null
+++ b/package/system/fstools/files/samba.hotplug
@@ -0,0 +1,47 @@
+logger $ACTION $DEVNAME $DEVTYPE
+
+[ "$ACTION" = "add" ] && {
+ [ "$DEVTYPE" = "partition" -o "$DEVTYPE" = "disk" ] && {
+ [ "${DEVNAME:0:2}" = "sd" ] && {
+ [ "$(mount | grep $DEVNAME | cut -d ' ' -f1 | tr -d '\n')" = "/dev/$DEVNAME" ] && {
+ section=`/sbin/uci add samba sambashare`
+ /sbin/uci rename samba.$section=usb$DEVNAME
+ /sbin/uci set samba.usb$DEVNAME.name=usb$DEVNAME
+ /sbin/uci set samba.usb$DEVNAME.path=/mnt/$DEVNAME
+ /sbin/uci set samba.usb$DEVNAME.read_only=no
+ /sbin/uci set samba.usb$DEVNAME.guest_ok=yes
+ /sbin/uci set samba.usb$DEVNAME.create_mask=777
+ /sbin/uci set samba.usb$DEVNAME.dir_mask=777
+ /sbin/uci commit
+ chmod 777 /mnt/$DEVNAME
+
+ touch /tmp/smb.flag
+ smp.sh storage
+
+ /etc/init.d/samba restart
+ }
+ }
+ }
+}
+
+[ "$ACTION" = "remove" ] && {
+ [ "$DEVTYPE" = "partition" -o "$DEVTYPE" = "disk" ] && {
+ [ "${DEVNAME:0:2}" = "sd" ] && {
+ [ `/sbin/uci get samba.usb$DEVNAME.name` = "" ] && break
+ [ `/sbin/uci get samba.usb$DEVNAME.name` = "usb$DEVNAME" ] && {
+ /sbin/uci delete samba.usb$DEVNAME
+ /sbin/uci commit
+ }
+ ret=$(/sbin/uci get samba.@sambashare[0] 2>&1 | awk '{print $3}' | tr -d '\n')
+ [ $ret = "not" ] && {
+ /etc/init.d/samba stop
+ rm -f /tmp/smb.flag
+ }
+ [ $ret = "not" ] || {
+ /etc/init.d/samba restart
+ }
+ }
+ }
+}
+
+
diff --git a/package/system/fstools/patches/001-usb-auto-mount.patch b/package/system/fstools/patches/001-usb-auto-mount.patch
new file mode 100644
index 0000000..1ad0c9c
--- /dev/null
+++ b/package/system/fstools/patches/001-usb-auto-mount.patch
@@ -0,0 +1,227 @@
+Index: fstools-2015-02-25.1/block.c
+===================================================================
+--- fstools-2015-02-25.1.orig/block.c
++++ fstools-2015-02-25.1/block.c
+@@ -21,6 +21,7 @@
+ #include <glob.h>
+ #include <dirent.h>
+ #include <stdarg.h>
++#include <errno.h>
+ #include <string.h>
+
+ #include <sys/stat.h>
+@@ -279,7 +280,7 @@ static int mount_add(struct uci_section
+ struct blob_attr *tb[__MOUNT_MAX] = { 0 };
+ struct mount *m;
+
+- blob_buf_init(&b, 0);
++ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, &mount_attr_list);
+ blobmsg_parse(mount_policy, __MOUNT_MAX, tb, blob_data(b.head), blob_len(b.head));
+
+@@ -319,7 +320,7 @@ static int swap_add(struct uci_section *
+ struct blob_attr *tb[__SWAP_MAX] = { 0 };
+ struct mount *m;
+
+- blob_buf_init(&b, 0);
++ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, &swap_attr_list);
+ blobmsg_parse(swap_policy, __SWAP_MAX, tb, blob_data(b.head), blob_len(b.head));
+
+@@ -357,7 +358,7 @@ static int global_add(struct uci_section
+ {
+ struct blob_attr *tb[__CFG_MAX] = { 0 };
+
+- blob_buf_init(&b, 0);
++ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, &config_attr_list);
+ blobmsg_parse(config_policy, __CFG_MAX, tb, blob_data(b.head), blob_len(b.head));
+
+@@ -414,6 +415,13 @@ static struct mount* find_block(const ch
+ return m;
+ if (m->device && device && !strcmp(m->device, device))
+ return m;
++ /* try wildcard match */
++ if (m->device && device && strchr(m->device, '*'))
++ {
++ char * p = strchr(m->device, '*');
++ if (0 == strncmp(device, m->device, p - m->device))
++ return m;
++ }
+ }
+
+ return NULL;
+@@ -745,6 +753,7 @@ static int mount_device(struct blkid_str
+ char *target = m->target;
+ char _target[32];
+ int err = 0;
++ uint32_t mflags = m->flags;
+
+ if (!target) {
+ snprintf(_target, sizeof(_target), "/mnt/%s", device);
+@@ -755,19 +764,34 @@ static int mount_device(struct blkid_str
+ if (check_fs)
+ check_filesystem(pr);
+
+- err = mount(pr->dev, target, pr->id->name, m->flags,
+- (m->options) ? (m->options) : (""));
+- if (err)
+- ERROR("mounting %s (%s) as %s failed (%d) - %s\n",
+- pr->dev, pr->id->name, target, err, strerror(err));
+- else
+- handle_swapfiles(true);
++ while (1) {
++ err = mount(pr->dev, target, pr->id->name, mflags,
++ (m->options) ? (m->options) : (""));
++ if (err) {
++ if (!(mflags & MS_RDONLY))
++ {
++ ERROR("Fall back on RO mount. %s.\n", strerror(errno));
++ mflags |= MS_RDONLY;
++ continue;
++ }
++ else {
++ ERROR("mounting %s (%s) as %s failed (%d) - %s\n",
++ pr->dev, pr->id->name, target, err, strerror(errno));
++ break;
++ }
++ }
++ else {
++ handle_swapfiles(true);
++ break;
++ }
++ }
+ return err;
+ }
+
+ if (anon_mount) {
+ char target[] = "/mnt/mmcblk123";
+ int err = 0;
++ uint32_t mflags = 0;
+
+ snprintf(target, sizeof(target), "/mnt/%s", device);
+ mkdir_p(target);
+@@ -775,12 +799,25 @@ static int mount_device(struct blkid_str
+ if (check_fs)
+ check_filesystem(pr);
+
+- err = mount(pr->dev, target, pr->id->name, 0, "");
+- if (err)
+- ERROR("mounting %s (%s) as %s failed (%d) - %s\n",
+- pr->dev, pr->id->name, target, err, strerror(err));
+- else
+- handle_swapfiles(true);
++ while (1) {
++ err = mount(pr->dev, target, pr->id->name, mflags, "");
++ if (err) {
++ if (!(mflags & MS_RDONLY)) {
++ ERROR("Fall back on RO mount. %s.\n", strerror(errno));
++ mflags |= MS_RDONLY;
++ continue;
++ }
++ else {
++ ERROR("mounting %s (%s) as %s failed (%d) - %s\n",
++ pr->dev, pr->id->name, target, err, strerror(errno));
++ break;
++ }
++ }
++ else {
++ handle_swapfiles(true);
++ break;
++ }
++ }
+ return err;
+ }
+
+@@ -811,7 +848,7 @@ static int umount_device(struct blkid_st
+ err = umount2(mp, MNT_DETACH);
+ if (err)
+ ERROR("unmounting %s (%s) failed (%d) - %s\n",
+- pr->dev, mp, err, strerror(err));
++ pr->dev, mp, err, strerror(errno));
+ else
+ ERROR("unmounted %s (%s)\n",
+ pr->dev, mp);
+@@ -839,7 +876,7 @@ static int main_hotplug(int argc, char *
+
+ if (err)
+ ERROR("umount of %s failed (%d) - %s\n",
+- mount_point, err, strerror(err));
++ mount_point, err, strerror(errno));
+
+ return 0;
+ } else if (strcmp(action, "add")) {
+@@ -1034,7 +1071,7 @@ static int check_extroot(char *path)
+ fp = fopen(tag, "w+");
+ if (!fp) {
+ ERROR("extroot: failed to write UUID to %s: %d (%s)\n",
+- tag, errno, strerror(errno));
++ tag, errno, strerror(errno));
+ /* return 0 to continue boot regardless of error */
+ return 0;
+ }
+@@ -1046,7 +1083,7 @@ static int check_extroot(char *path)
+ fp = fopen(tag, "r");
+ if (!fp) {
+ ERROR("extroot: failed to read UUID from %s: %d (%s)\n",
+- tag, errno, strerror(errno));
++ tag, errno, strerror(errno));
+ return -1;
+ }
+
+@@ -1057,7 +1094,7 @@ static int check_extroot(char *path)
+ return 0;
+
+ ERROR("extroot: UUID mismatch (root: %s, %s: %s)\n",
+- pr->uuid, basename(path), uuid);
++ pr->uuid, basename(path), uuid);
+ return -1;
+ }
+ }
+@@ -1105,7 +1142,7 @@ static int mount_extroot(char *cfg)
+ }
+ if (pr) {
+ if (strncmp(pr->id->name, "ext", 3) &&
+- strncmp(pr->id->name, "ubifs", 5)) {
++ strncmp(pr->id->name, "ubifs", 5)) {
+ ERROR("extroot: unsupported filesystem %s, try ext4\n", pr->id->name);
+ return -1;
+ }
+@@ -1126,7 +1163,7 @@ static int mount_extroot(char *cfg)
+
+ if (err) {
+ ERROR("extroot: mounting %s (%s) on %s failed: %d (%s)\n",
+- pr->dev, pr->id->name, path, err, strerror(err));
++ pr->dev, pr->id->name, path, err, strerror(errno));
+ } else if (m->overlay) {
+ err = check_extroot(path);
+ if (err)
+@@ -1134,8 +1171,8 @@ static int mount_extroot(char *cfg)
+ }
+ } else {
+ ERROR("extroot: cannot find device %s%s\n",
+- (m->uuid ? "with UUID " : (m->label ? "with label " : "")),
+- (m->uuid ? m->uuid : (m->label ? m->label : m->device)));
++ (m->uuid ? "with UUID " : (m->label ? "with label " : "")),
++ (m->uuid ? m->uuid : (m->label ? m->label : m->device)));
+ }
+
+ return err;
+@@ -1210,7 +1247,7 @@ static int main_extroot(int argc, char *
+ rmdir("/tmp/overlay");
+ rmdir(cfg);
+ return err;
+- }
++ }
+ #endif
+
+ return mount_extroot(NULL);
+@@ -1255,7 +1292,7 @@ static int main_detect(int argc, char **
+ cache_load(0);
+ printf("config 'global'\n");
+ printf("\toption\tanon_swap\t'0'\n");
+- printf("\toption\tanon_mount\t'0'\n");
++ printf("\toption\tanon_mount\t'1'\n");
+ printf("\toption\tauto_swap\t'1'\n");
+ printf("\toption\tauto_mount\t'1'\n");
+ printf("\toption\tdelay_root\t'5'\n");
diff --git a/package/system/fstools/patches/002-ntfs-exfat.patch b/package/system/fstools/patches/002-ntfs-exfat.patch
new file mode 100644
index 0000000..3d8c7e5
--- /dev/null
+++ b/package/system/fstools/patches/002-ntfs-exfat.patch
@@ -0,0 +1,525 @@
+Index: fstools-2015-02-25.1/CMakeLists.txt
+===================================================================
+--- fstools-2015-02-25.1.orig/CMakeLists.txt
++++ fstools-2015-02-25.1/CMakeLists.txt
+@@ -23,6 +23,8 @@ ADD_LIBRARY(blkid-tiny SHARED
+ libblkid-tiny/ext.c
+ libblkid-tiny/jffs2.c
+ libblkid-tiny/vfat.c
++ libblkid-tiny/ntfs.c
++ libblkid-tiny/exfat.c
+ libblkid-tiny/hfs.c
+ libblkid-tiny/swap.c
+ libblkid-tiny/ubifs.c
+Index: fstools-2015-02-25.1/libblkid-tiny/libblkid-tiny.c
+===================================================================
+--- fstools-2015-02-25.1.orig/libblkid-tiny/libblkid-tiny.c
++++ fstools-2015-02-25.1/libblkid-tiny/libblkid-tiny.c
+@@ -10,6 +10,8 @@
+ #define DEBUG(fmt, ...)
+ #endif
+
++#define isspace(x) ((x == ' ') || (x == '\t') || (x == '\r') || (x == '\n'))
++
+ int blkid_debug_mask = 0;
+
+ static unsigned char *probe_buffer;
+@@ -152,9 +154,77 @@ int blkid_probe_sprintf_uuid(blkid_probe
+ return 0;
+ }
+
++size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len,
++ const unsigned char *src, size_t count)
++{
++ size_t i, j;
++ uint16_t c;
++
++ for (j = i = 0; i + 2 <= count; i += 2)
++ {
++ if (enc == BLKID_ENC_UTF16LE)
++ c = (src[i+1] << 8) | src[i];
++ else /* BLKID_ENC_UTF16BE */
++ c = (src[i] << 8) | src[i+1];
++ if (c == 0)
++ {
++ dest[j] = '\0';
++ break;
++ }
++ else if (c < 0x80)
++ {
++ if (j+1 >= len)
++ break;
++ dest[j++] = (uint8_t) c;
++ }
++ else if (c < 0x800)
++ {
++ if (j+2 >= len)
++ break;
++ dest[j++] = (uint8_t) (0xc0 | (c >> 6));
++ dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
++ }
++ else
++ {
++ if (j+3 >= len)
++ break;
++ dest[j++] = (uint8_t) (0xe0 | (c >> 12));
++ dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
++ dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
++ }
++ }
++ dest[j] = '\0';
++ return j;
++}
++
++size_t blkid_rtrim_whitespace(unsigned char *str)
++{
++ size_t i = strlen((char *) str);
++
++ while (i--)
++ {
++ if (!isspace(str[i]))
++ break;
++ }
++ str[++i] = '\0';
++ return i;
++}
++
++int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
++ size_t len, int enc)
++{
++ blkid_encode_to_utf8(enc, (unsigned char *) pr->label, sizeof(pr->label), label, len);
++ blkid_rtrim_whitespace((unsigned char *) pr->label);
++ return 0;
++}
++
++
++
+ static const struct blkid_idinfo *idinfos[] =
+ {
+ &vfat_idinfo,
++ &ntfs_idinfo,
++ &exfat_idinfo,
+ &swsuspend_idinfo,
+ &swap_idinfo,
+ &ext4dev_idinfo,
+Index: fstools-2015-02-25.1/libblkid-tiny/ntfs.c
+===================================================================
+--- /dev/null
++++ fstools-2015-02-25.1/libblkid-tiny/ntfs.c
+@@ -0,0 +1,246 @@
++/*
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <inttypes.h>
++
++#include "superblocks.h"
++
++struct ntfs_bios_parameters
++{
++ uint16_t sector_size; /* Size of a sector in bytes. */
++ uint8_t sectors_per_cluster; /* Size of a cluster in sectors. */
++ uint16_t reserved_sectors; /* zero */
++ uint8_t fats; /* zero */
++ uint16_t root_entries; /* zero */
++ uint16_t sectors; /* zero */
++ uint8_t media_type; /* 0xf8 = hard disk */
++ uint16_t sectors_per_fat; /* zero */
++ uint16_t sectors_per_track; /* irrelevant */
++ uint16_t heads; /* irrelevant */
++ uint32_t hidden_sectors; /* zero */
++ uint32_t large_sectors; /* zero */
++} __attribute__ ((__packed__));
++
++struct ntfs_super_block
++{
++ uint8_t jump[3];
++ uint8_t oem_id[8]; /* magic string */
++
++ struct ntfs_bios_parameters bpb;
++
++ uint16_t unused[2];
++ uint64_t number_of_sectors;
++ uint64_t mft_cluster_location;
++ uint64_t mft_mirror_cluster_location;
++ int8_t clusters_per_mft_record;
++ uint8_t reserved1[3];
++ int8_t cluster_per_index_record;
++ uint8_t reserved2[3];
++ uint64_t volume_serial;
++ uint32_t checksum;
++} __attribute__((packed));
++
++struct master_file_table_record
++{
++ uint32_t magic;
++ uint16_t usa_ofs;
++ uint16_t usa_count;
++ uint64_t lsn;
++ uint16_t sequence_number;
++ uint16_t link_count;
++ uint16_t attrs_offset;
++ uint16_t flags;
++ uint32_t bytes_in_use;
++ uint32_t bytes_allocated;
++} __attribute__((__packed__));
++
++struct file_attribute
++{
++ uint32_t type;
++ uint32_t len;
++ uint8_t non_resident;
++ uint8_t name_len;
++ uint16_t name_offset;
++ uint16_t flags;
++ uint16_t instance;
++ uint32_t value_len;
++ uint16_t value_offset;
++} __attribute__((__packed__));
++
++#define MFT_RECORD_VOLUME 3
++#define NTFS_MAX_CLUSTER_SIZE (64 * 1024)
++
++enum
++{
++ MFT_RECORD_ATTR_VOLUME_NAME = 0x60,
++ MFT_RECORD_ATTR_END = 0xffffffff
++};
++
++static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
++{
++ struct ntfs_super_block *ns;
++ struct master_file_table_record *mft;
++
++ uint32_t sectors_per_cluster, mft_record_size, attr_off;
++ uint16_t sector_size;
++ uint64_t nr_clusters, off;
++ unsigned char *buf_mft;
++
++ ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
++ if (!ns)
++ return -1;
++
++ /*
++ * Check bios parameters block
++ */
++ sector_size = le16_to_cpu(ns->bpb.sector_size);
++ sectors_per_cluster = ns->bpb.sectors_per_cluster;
++
++ if (sector_size < 256 || sector_size > 4096)
++ return 1;
++
++ switch (sectors_per_cluster)
++ {
++ case 1:
++ case 2:
++ case 4:
++ case 8:
++ case 16:
++ case 32:
++ case 64:
++ case 128:
++ break;
++ default:
++ return 1;
++ }
++
++ if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) *
++ ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE)
++ return 1;
++
++ /* Unused fields must be zero */
++ if (le16_to_cpu(ns->bpb.reserved_sectors)
++ || le16_to_cpu(ns->bpb.root_entries)
++ || le16_to_cpu(ns->bpb.sectors)
++ || le16_to_cpu(ns->bpb.sectors_per_fat)
++ || le32_to_cpu(ns->bpb.large_sectors)
++ || ns->bpb.fats)
++ return 1;
++
++ if ((uint8_t) ns->clusters_per_mft_record < 0xe1
++ || (uint8_t) ns->clusters_per_mft_record > 0xf7)
++ {
++
++ switch (ns->clusters_per_mft_record)
++ {
++ case 1:
++ case 2:
++ case 4:
++ case 8:
++ case 16:
++ case 32:
++ case 64:
++ break;
++ default:
++ return 1;
++ }
++ }
++
++ if (ns->clusters_per_mft_record > 0)
++ mft_record_size = ns->clusters_per_mft_record *
++ sectors_per_cluster * sector_size;
++ else
++ mft_record_size = 1 << (0 - ns->clusters_per_mft_record);
++
++ nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
++
++ if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
++ (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
++ return 1;
++
++
++ off = le64_to_cpu(ns->mft_cluster_location) * sector_size *
++ sectors_per_cluster;
++
++ DBG(DEBUG_LOWPROBE, printf("NTFS: sector_size=%d, mft_record_size=%d, "
++ "sectors_per_cluster=%d, nr_clusters=%ju "
++ "cluster_offset=%jd",
++ (int) sector_size, mft_record_size,
++ sectors_per_cluster, nr_clusters,
++ off));
++
++ buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
++ if (!buf_mft)
++ return 1;
++
++ if (memcmp(buf_mft, "FILE", 4))
++ return 1;
++
++ off += MFT_RECORD_VOLUME * mft_record_size;
++
++ buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
++ if (!buf_mft)
++ return 1;
++
++ if (memcmp(buf_mft, "FILE", 4))
++ return 1;
++
++ mft = (struct master_file_table_record *) buf_mft;
++ attr_off = le16_to_cpu(mft->attrs_offset);
++
++ while (attr_off < mft_record_size &&
++ attr_off <= le32_to_cpu(mft->bytes_allocated))
++ {
++
++ uint32_t attr_len;
++ struct file_attribute *attr;
++
++ attr = (struct file_attribute *) (buf_mft + attr_off);
++ attr_len = le32_to_cpu(attr->len);
++ if (!attr_len)
++ break;
++
++ if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_END)
++ break;
++ if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_VOLUME_NAME)
++ {
++ unsigned int val_off = le16_to_cpu(attr->value_offset);
++ unsigned int val_len = le32_to_cpu(attr->value_len);
++ unsigned char *val = ((uint8_t *) attr) + val_off;
++
++ blkid_probe_set_utf8label(pr, val, val_len, BLKID_ENC_UTF16LE);
++ break;
++ }
++
++ if (UINT_MAX - attr_len < attr_off)
++ break;
++ attr_off += attr_len;
++ }
++
++ blkid_probe_sprintf_uuid(pr,
++ (unsigned char *) &ns->volume_serial,
++ sizeof(ns->volume_serial),
++ "%016" PRIX64, le64_to_cpu(ns->volume_serial));
++ return 0;
++}
++
++
++const struct blkid_idinfo ntfs_idinfo =
++{
++ .name = "ntfs",
++ .usage = BLKID_USAGE_FILESYSTEM,
++ .probefunc = probe_ntfs,
++ .magics =
++ {
++ { .magic = "NTFS ", .len = 5, .sboff = 3 },
++ { NULL }
++ }
++};
+Index: fstools-2015-02-25.1/libblkid-tiny/exfat.c
+===================================================================
+--- /dev/null
++++ fstools-2015-02-25.1/libblkid-tiny/exfat.c
+@@ -0,0 +1,151 @@
++/*
++ * Copyright (C) 2010 Andrew Nayenko <resver@gmail.com>
++ *
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ */
++#include "superblocks.h"
++
++struct exfat_super_block
++{
++ uint8_t jump[3];
++ uint8_t oem_name[8];
++ uint8_t __unused1[53];
++ uint64_t block_start;
++ uint64_t block_count;
++ uint32_t fat_block_start;
++ uint32_t fat_block_count;
++ uint32_t cluster_block_start;
++ uint32_t cluster_count;
++ uint32_t rootdir_cluster;
++ uint8_t volume_serial[4];
++ struct
++ {
++ uint8_t minor;
++ uint8_t major;
++ } version;
++ uint16_t volume_state;
++ uint8_t block_bits;
++ uint8_t bpc_bits;
++ uint8_t fat_count;
++ uint8_t drive_no;
++ uint8_t allocated_percent;
++} __attribute__((__packed__));
++
++struct exfat_entry_label
++{
++ uint8_t type;
++ uint8_t length;
++ uint8_t name[30];
++} __attribute__((__packed__));
++
++#define BLOCK_SIZE(sb) (1 << (sb)->block_bits)
++#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits)
++#define EXFAT_FIRST_DATA_CLUSTER 2
++#define EXFAT_LAST_DATA_CLUSTER 0xffffff6
++#define EXFAT_ENTRY_SIZE 32
++
++#define EXFAT_ENTRY_EOD 0x00
++#define EXFAT_ENTRY_LABEL 0x83
++
++static blkid_loff_t block_to_offset(const struct exfat_super_block *sb,
++ blkid_loff_t block)
++{
++ return (blkid_loff_t) block << sb->block_bits;
++}
++
++static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb,
++ uint32_t cluster)
++{
++ return le32_to_cpu(sb->cluster_block_start) +
++ ((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER)
++ << sb->bpc_bits);
++}
++
++static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb,
++ uint32_t cluster)
++{
++ return block_to_offset(sb, cluster_to_block(sb, cluster));
++}
++
++static uint32_t next_cluster(blkid_probe pr,
++ const struct exfat_super_block *sb, uint32_t cluster)
++{
++ uint32_t *next;
++ blkid_loff_t fat_offset;
++
++ fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start))
++ + (blkid_loff_t) cluster * sizeof(cluster);
++ next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset,
++ sizeof(uint32_t));
++ if (!next)
++ return 0;
++ return le32_to_cpu(*next);
++}
++
++static struct exfat_entry_label *find_label(blkid_probe pr,
++ const struct exfat_super_block *sb)
++{
++ uint32_t cluster = le32_to_cpu(sb->rootdir_cluster);
++ blkid_loff_t offset = cluster_to_offset(sb, cluster);
++ uint8_t *entry;
++
++ for (;;)
++ {
++ entry = (uint8_t *) blkid_probe_get_buffer(pr, offset,
++ EXFAT_ENTRY_SIZE);
++ if (!entry)
++ return NULL;
++ if (entry[0] == EXFAT_ENTRY_EOD)
++ return NULL;
++ if (entry[0] == EXFAT_ENTRY_LABEL)
++ return (struct exfat_entry_label *) entry;
++ offset += EXFAT_ENTRY_SIZE;
++ if (offset % CLUSTER_SIZE(sb) == 0)
++ {
++ cluster = next_cluster(pr, sb, cluster);
++ if (cluster < EXFAT_FIRST_DATA_CLUSTER)
++ return NULL;
++ if (cluster > EXFAT_LAST_DATA_CLUSTER)
++ return NULL;
++ offset = cluster_to_offset(sb, cluster);
++ }
++ }
++}
++
++static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag)
++{
++ struct exfat_super_block *sb;
++ struct exfat_entry_label *label;
++
++ sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block);
++ if (!sb)
++ return -1;
++
++ blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4,
++ "%02hhX%02hhX-%02hhX%02hhX",
++ sb->volume_serial[3], sb->volume_serial[2],
++ sb->volume_serial[1], sb->volume_serial[0]);
++
++ blkid_probe_sprintf_version(pr, "%u.%u",
++ sb->version.major, sb->version.minor);
++
++ label = find_label(pr, sb);
++ if (label)
++ blkid_probe_set_utf8label(pr, label->name,
++ min(label->length * 2, 30), BLKID_ENC_UTF16LE);
++
++ return 0;
++}
++
++const struct blkid_idinfo exfat_idinfo =
++{
++ .name = "exfat",
++ .usage = BLKID_USAGE_FILESYSTEM,
++ .probefunc = probe_exfat,
++ .magics =
++ {
++ { .magic = "EXFAT ", .len = 8, .sboff = 3 },
++ { NULL }
++ }
++};
+Index: fstools-2015-02-25.1/libblkid-tiny/superblocks.h
+===================================================================
+--- fstools-2015-02-25.1.orig/libblkid-tiny/superblocks.h
++++ fstools-2015-02-25.1/libblkid-tiny/superblocks.h
+@@ -87,6 +87,8 @@ extern int blkid_probe_strncpy_uuid(blki
+
+ extern int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid);
+ extern int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name);
+-
++extern size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len,
++ const unsigned char *src, size_t count);
++
+
+ #endif /* _BLKID_SUPERBLOCKS_H */
diff --git a/package/system/fstools/patches/003-nand-jffs2.patch b/package/system/fstools/patches/003-nand-jffs2.patch
new file mode 100644
index 0000000..17c5afa
--- /dev/null
+++ b/package/system/fstools/patches/003-nand-jffs2.patch
@@ -0,0 +1,13 @@
+Index: fstools-2015-02-25.1/libfstools/mtd.c
+===================================================================
+--- fstools-2015-02-25.1.orig/libfstools/mtd.c
++++ fstools-2015-02-25.1/libfstools/mtd.c
+@@ -214,7 +214,7 @@ static int mtd_volume_identify(struct vo
+ return FS_JFFS2;
+ }
+
+- if (v->type == UBIVOLUME && deadc0de == 0xffffffff) {
++ if ((v->type == UBIVOLUME || v->type == NANDFLASH) && deadc0de == 0xffffffff) {
+ fprintf(stderr, "jffs2 is ready\n");
+ return FS_JFFS2;
+ }
diff --git a/package/system/fstools/patches/004-emmc.patch b/package/system/fstools/patches/004-emmc.patch
new file mode 100644
index 0000000..86b8ca7
--- /dev/null
+++ b/package/system/fstools/patches/004-emmc.patch
@@ -0,0 +1,597 @@
+Index: fstools-2015-02-25.1/mount_root.c
+===================================================================
+--- fstools-2015-02-25.1.orig/mount_root.c
++++ fstools-2015-02-25.1/mount_root.c
+@@ -62,6 +62,7 @@ start(int argc, char *argv[1])
+
+ case FS_JFFS2:
+ case FS_UBIFS:
++ case FS_EXT4:
+ mount_overlay(data);
+ break;
+
+@@ -89,6 +90,7 @@ static int
+ done(int argc, char *argv[1])
+ {
+ struct volume *v = volume_find("rootfs_data");
++ FILE * fp = NULL;
+
+ if (!v)
+ return -1;
+@@ -96,6 +98,19 @@ done(int argc, char *argv[1])
+ switch (volume_identify(v)) {
+ case FS_NONE:
+ case FS_DEADCODE:
++ /* if the mtd is created by block2mtd */
++ fp = fopen("/proc/cmdline", "rb");
++ if (fp) {
++ char buf[2048] = {0};
++ fread(buf, 1, sizeof(buf), fp);
++ fclose(fp);
++ buf[sizeof(buf)-1] = 0;
++ if (strstr(buf, "block2mtd")) {
++ fprintf(stderr, "%s is created by block2mtd, ext4_switch.\n", v->name);
++ return ext4_switch(v);
++ }
++ }
++ fprintf(stderr, "%s, normally, jffs2_switch.\n", v->name);
+ return jffs2_switch(v);
+ }
+
+@@ -104,8 +119,11 @@ done(int argc, char *argv[1])
+
+ int main(int argc, char **argv)
+ {
+- if (argc < 2)
++ if (argc < 2) {
++ fprintf(stderr, "%s.\n", argv[0]);
+ return start(argc, argv);
++ }
++ fprintf(stderr, "%s %s.\n", argv[0], argv[1]);
+ if (!strcmp(argv[1], "stop"))
+ return stop(argc, argv);
+ if (!strcmp(argv[1], "done"))
+Index: fstools-2015-02-25.1/libfstools/emmc.c
+===================================================================
+--- /dev/null
++++ fstools-2015-02-25.1/libfstools/emmc.c
+@@ -0,0 +1,272 @@
++/*
++ * Copyright (C) 2015 Hua Shao <nossiac@163.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1
++ * as published by the Free Software Foundation
++ *
++ * 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.
++ */
++
++#include <sys/mount.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <asm/byteorder.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <mtd/mtd-user.h>
++
++#include "libfstools.h"
++
++#include "volume.h"
++
++#define PATH_MAX 256
++
++struct emmc_priv {
++ int fd;
++ int idx;
++ char *chr;
++};
++
++static struct driver emmc_driver;
++
++
++static int emmc_partition_load(struct volume *v)
++{
++ struct emmc_priv *p = (struct emmc_priv*) v->priv;
++ struct mtd_info_user mtd_info;
++
++ fprintf(stderr, "%s(%s)\n", __FUNCTION__, v->name);
++ if (p->fd)
++ return 0;
++
++ p->fd = open(p->chr, O_RDWR | O_SYNC);
++ if (p->fd < 0) {
++ p->fd = 0;
++ fprintf(stderr, "Could not open block2mtd device: %s\n", p->chr);
++ return -1;
++ }
++
++ v->type = EMMC;
++
++ if (ioctl(p->fd, MEMGETINFO, &mtd_info)) {
++ close(p->fd);
++ fprintf(stderr, "Could not get MTD device info from %s(block2mtd)\n", p->chr);
++ v->size = 0; // TODO
++ v->block_size = -1; // TODO
++ }
++
++ v->size = mtd_info.size;
++ v->block_size = mtd_info.erasesize;
++
++ return 0;
++}
++
++
++static int block2mtd_find_index(char *name)
++{
++ FILE *fp = fopen("/proc/mtd", "r");
++ static char line[256];
++ char *index = NULL;
++
++ if(!fp)
++ return -1;
++
++ while (!index && fgets(line, sizeof(line), fp)) {
++ char *ret;
++
++ if ((ret = strstr(line, name)) && (ret[strlen(name)] == '"')) {
++ char *eol = strstr(line, ":");
++
++ if (!eol)
++ continue;
++
++ *eol = '\0';
++ index = &line[3];
++ }
++ }
++
++ fclose(fp);
++ if (index)
++ return atoi(index);
++ else
++ return -1;
++}
++
++
++static int emmc_partition_find(struct volume *v, char *name)
++{
++ struct emmc_priv *p;
++ static char buffer[32];
++ FILE * fp = NULL;
++
++ fprintf(stderr, "%s(%p, %s)\n", __FUNCTION__, v, name);
++
++ fp = fopen("/proc/cmdline", "rb");
++ if (fp) {
++ char buf[2048] = {0};
++ fread(buf, 1, sizeof(buf), fp);
++ fclose(fp);
++ buf[sizeof(buf)-1] = 0;
++ if (!strstr(buf, "block2mtd")) {
++ fprintf(stderr, "%s is not created by block2mtd, skip.\n", v->name);
++ return -1;
++ }
++ }
++
++ p = calloc(1, sizeof(struct emmc_priv));
++ if (!p)
++ return -1;
++
++ p->idx = block2mtd_find_index(name);
++
++ v->priv = p;
++ v->name = strdup(name);
++ v->drv = &emmc_driver;
++
++ snprintf(buffer, sizeof(buffer), "/dev/mtdblock%d", p->idx);
++ v->blk = strdup(buffer);
++
++ snprintf(buffer, sizeof(buffer), "/dev/mtd%d", p->idx);
++ p->chr = strdup(buffer);
++
++ if (emmc_partition_load(v)) {
++ fprintf(stderr, "%s emmc_partition_load %s failed\n", __FUNCTION__, v->name);
++ return -1;
++ }
++
++ fprintf(stderr, "v->name = %s\n", v->name);
++ fprintf(stderr, "v->blk = %s\n", v->blk);
++ fprintf(stderr, "v->drv->name = %s\n", v->drv->name);
++ fprintf(stderr, "v->priv->fd = %d\n", p->fd);
++ fprintf(stderr, "v->priv->idx = %d\n", p->idx);
++ fprintf(stderr, "v->priv->chr = %s\n", p->chr);
++
++ return 0;
++}
++
++static int emmc_partition_identify(struct volume *v)
++{
++ struct emmc_priv *p = (struct emmc_priv*) v->priv;
++ __u32 deadc0de;
++ __u16 ext4;
++ size_t sz;
++
++ fprintf(stderr, "%s(%s)\n", __FUNCTION__, v->name);
++ if (emmc_partition_load(v)) {
++ fprintf(stderr, "%s, emmc_partition_load %s failed\n", __FUNCTION__, v->name);
++ return -1;
++ }
++
++ sz = read(p->fd, &deadc0de, sizeof(deadc0de));
++ if (sz != sizeof(deadc0de)) {
++ fprintf(stderr, "%s, reading %s failed: %s\n", __FUNCTION__, v->name, strerror(errno));
++ return -1;
++ }
++
++ deadc0de = __be32_to_cpu(deadc0de);
++ if (deadc0de == 0xdeadc0de) {
++ fprintf(stderr, "ext4 is not ready - marker found\n");
++ return FS_DEADCODE;
++ }
++
++ /* 0x400 -> super block offset in partition
++ 0x38 -> magic offset in superblock
++ */
++ lseek(p->fd, 0x438, SEEK_SET);
++ sz = read(p->fd, &ext4, sizeof(ext4));
++ if (sz != sizeof(ext4)) {
++ fprintf(stderr, "reading %s failed: %s\n", v->name, strerror(errno));
++ return -1;
++ }
++
++ if (ext4 == 0xEF53) {
++ fprintf(stderr, "ext4 is ready\n");
++ return FS_EXT4;
++ }
++
++ fprintf(stderr, "No ext4 magic was found, expected %x, got %x\n", 0xEF53, ext4);
++
++ return FS_NONE;
++}
++
++static int emmc_partition_erase(struct volume *v, int offset, int len)
++{
++ fprintf(stderr, "%s(%s, %d, %d)\n", __FUNCTION__, v->name, offset, len);
++ return 0;
++}
++
++static int emmc_partition_erase_all(struct volume *v)
++{
++ fprintf(stderr, "%s, remove files instead of erase partitions.\n", __FUNCTION__);
++ system("rm -rf /overlay/*");
++ return 0;
++}
++
++static int emmc_partition_init(struct volume *v)
++{
++ fprintf(stderr, "%s(%s)\n", __FUNCTION__, v->name);
++ return 0;
++}
++
++static int emmc_partition_read(struct volume *v, void *buf, int offset, int length)
++{
++ struct emmc_priv *p = (struct emmc_priv*) v->priv;
++
++ fprintf(stderr, "%s(%s, %p, %d, %d)\n", __FUNCTION__, v->name, buf, offset, length);
++ if (emmc_partition_load(v))
++ return -1;
++
++ if (lseek(p->fd, offset, SEEK_SET) == (off_t) -1) {
++ fprintf(stderr, "lseek/read failed\n");
++ return -1;
++ }
++
++ if (read(p->fd, buf, length) == -1) {
++ fprintf(stderr, "read failed\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++static int emmc_partition_write(struct volume *v, void *buf, int offset, int length)
++{
++
++ fprintf(stderr, "%s(%s, %p, %d, %d)\n", __FUNCTION__, v->name, buf, offset, length);
++
++#if 0
++ struct emmc_priv *p = (struct emmc_priv*) v->priv;
++ if (emmc_partition_load(v))
++ return -1;
++
++ if (lseek(p->fd, offset, SEEK_SET) == (off_t) -1) {
++ fprintf(stderr, "lseek/write failed at offset %d\n", offset);
++ perror("lseek");
++ return -1;
++ }
++
++ if (write(p->fd, buf, length) == -1) {
++ fprintf(stderr, "write failed\n");
++ return -1;
++ }
++#endif
++ return 0;
++}
++
++static struct driver emmc_driver = {
++ .name = "emmc",
++ .find = emmc_partition_find,
++ .init = emmc_partition_init,
++ .erase = emmc_partition_erase,
++ .erase_all = emmc_partition_erase_all,
++ .read = emmc_partition_read,
++ .write = emmc_partition_write,
++ .identify = emmc_partition_identify,
++};
++DRIVER(emmc_driver);
+Index: fstools-2015-02-25.1/libfstools/libfstools.h
+===================================================================
+--- fstools-2015-02-25.1.orig/libfstools/libfstools.h
++++ fstools-2015-02-25.1/libfstools/libfstools.h
+@@ -25,6 +25,7 @@ enum {
+ FS_JFFS2,
+ FS_DEADCODE,
+ FS_UBIFS,
++ FS_EXT4,
+ };
+
+ extern char const *extroot_prefix;
+@@ -43,6 +44,7 @@ extern char* find_mount_point(char *bloc
+ extern int find_filesystem(char *fs);
+
+ extern int jffs2_switch(struct volume *v);
++extern int ext4_switch(struct volume *v);
+
+ extern int handle_whiteout(const char *dir);
+ extern void foreachdir(const char *dir, int (*cb)(const char*));
+Index: fstools-2015-02-25.1/libfstools/volume.h
+===================================================================
+--- fstools-2015-02-25.1.orig/libfstools/volume.h
++++ fstools-2015-02-25.1/libfstools/volume.h
+@@ -47,6 +47,7 @@ enum {
+ NANDFLASH,
+ NORFLASH,
+ UBIVOLUME,
++ EMMC,
+ };
+
+ struct volume {
+Index: fstools-2015-02-25.1/libfstools/overlay.c
+===================================================================
+--- fstools-2015-02-25.1.orig/libfstools/overlay.c
++++ fstools-2015-02-25.1/libfstools/overlay.c
+@@ -31,6 +31,7 @@
+ #include "volume.h"
+
+ #define SWITCH_JFFS2 "/tmp/.switch_jffs2"
++#define SWITCH_EXT4 "/tmp/.switch_ext4"
+
+ void
+ foreachdir(const char *dir, int (*cb)(const char*))
+@@ -106,6 +107,59 @@ switch2jffs(struct volume *v)
+ return fopivot("/overlay", "/rom");
+ }
+
++
++static int
++switch2ext4(struct volume *v)
++{
++ struct stat s;
++ int ret;
++
++ if (!stat(SWITCH_EXT4, &s)) {
++ fprintf(stderr, "ext4 switch already running\n");
++ return -1;
++ }
++
++ creat(SWITCH_EXT4, 0600);
++ ret = mount(v->blk, "/rom/overlay", "ext4", MS_NOATIME, NULL);
++ unlink(SWITCH_EXT4);
++ if (ret) {
++ fprintf(stderr, "failed - mount -t ext4 %s /rom/overlay: %s\n", v->blk, strerror(errno));
++
++ char buf[128] = {0};
++ fprintf(stderr, "maybe ext4 is not created yet.\n");
++ snprintf(buf, sizeof(buf), "mkfs.ext4 %s", v->blk);
++ system(buf);
++ fprintf(stderr, "%s.\n", buf);
++
++ creat(SWITCH_EXT4, 0600);
++ ret = mount(v->blk, "/rom/overlay", "ext4", MS_NOATIME, NULL);
++ unlink(SWITCH_EXT4);
++ if (ret) {
++ fprintf(stderr, "failed again, give up - mount -t ext4 %s /rom/overlay: %s\n", v->blk, strerror(errno));
++ return -1;
++ }
++ }
++
++ if (mount("none", "/", NULL, MS_NOATIME | MS_REMOUNT, 0)) {
++ fprintf(stderr, "failed - mount -o remount,ro none: %s\n", strerror(errno));
++ return -1;
++ }
++
++ system("cp -a /tmp/root/* /rom/overlay");
++
++ if (pivot("/rom", "/mnt")) {
++ fprintf(stderr, "failed - pivot /rom /mnt: %s\n", strerror(errno));
++ return -1;
++ }
++
++ if (mount_move("/mnt", "/tmp/root", "")) {
++ fprintf(stderr, "failed - mount -o move /mnt /tmp/root %s\n", strerror(errno));
++ return -1;
++ }
++
++ return fopivot("/overlay", "/rom");
++}
++
+ int
+ handle_whiteout(const char *dir)
+ {
+@@ -199,6 +253,53 @@ jffs2_switch(struct volume *v)
+ return ret;
+ }
+
++int
++ext4_switch(struct volume *v)
++{
++ char *mp;
++ int ret = -1;
++
++ if (find_overlay_mount("overlayfs:/tmp/root"))
++ return -1;
++
++ if (find_filesystem("overlay")) {
++ fprintf(stderr, "overlayfs not found\n");
++ return ret;
++ }
++
++ mp = find_mount_point(v->blk, 0);
++ if (mp) {
++ fprintf(stderr, "rootfs_data:%s is already mounted as %s\n", v->blk, mp);
++ return -1;
++ }
++
++ switch (volume_identify(v)) {
++ case FS_NONE:
++ fprintf(stderr, "no ext4 marker found\n");
++ /* fall through */
++
++ case FS_DEADCODE:
++ ret = switch2ext4(v);
++ if (!ret) {
++ fprintf(stderr, "doing fo cleanup\n");
++ umount2("/tmp/root", MNT_DETACH);
++ foreachdir("/overlay/", handle_whiteout);
++ }
++ break;
++
++ case FS_EXT4:
++ ret = overlay_mount(v, "ext4");
++ if (ret)
++ break;
++ if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) {
++ fprintf(stderr, "switching to ext4 failed\n");
++ ret = -1;
++ }
++ break;
++ }
++ return ret;
++}
++
+ static int overlay_mount_fs(struct volume *v)
+ {
+ char *fstype;
+@@ -214,12 +315,29 @@ static int overlay_mount_fs(struct volum
+ case FS_UBIFS:
+ fstype = "ubifs";
+ break;
++ case FS_EXT4:
++ fstype = "ext4";
++ break;
+ }
+
+ if (mount(v->blk, "/tmp/overlay", fstype, MS_NOATIME, NULL)) {
+ fprintf(stderr, "failed to mount -t %s %s /tmp/overlay: %s\n",
+ fstype, v->blk, strerror(errno));
+- return -1;
++
++ if (0 == strcmp(fstype, "ext4")) {
++ /* maybe ext4 is not created yet! */
++ char buf[128] = {0};
++ fprintf(stderr, "maybe ext4 is not created yet.\n");
++ snprintf(buf, sizeof(buf), "mkfs.ext4 %s", v->blk);
++ system(buf);
++ fprintf(stderr, "%s.\n", buf);
++
++ if (mount(v->blk, "/tmp/overlay", fstype, MS_NOATIME, NULL)) {
++ fprintf(stderr, "again! failed to mount -t %s %s /tmp/overlay: %s\n",
++ fstype, v->blk, strerror(errno));
++ return -1;
++ }
++ }
+ }
+
+ volume_init(v);
+@@ -250,7 +368,7 @@ int mount_overlay(struct volume *v)
+
+ fprintf(stderr, "switching to overlay\n");
+ if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) {
+- fprintf(stderr, "switching to jffs2 failed - fallback to ramoverlay\n");
++ fprintf(stderr, "switching to overlay failed - fallback to ramoverlay\n");
+ return ramoverlay();
+ }
+
+Index: fstools-2015-02-25.1/CMakeLists.txt
+===================================================================
+--- fstools-2015-02-25.1.orig/CMakeLists.txt
++++ fstools-2015-02-25.1/CMakeLists.txt
+@@ -10,6 +10,7 @@ ADD_LIBRARY(fstools SHARED
+ libfstools/extroot.c
+ libfstools/overlay.c
+ libfstools/volume.c
++ libfstools/emmc.c
+ libfstools/mtd.c
+ libfstools/mount.c
+ libfstools/ubi.c
+Index: fstools-2015-02-25.1/libfstools/mtd.c
+===================================================================
+--- fstools-2015-02-25.1.orig/libfstools/mtd.c
++++ fstools-2015-02-25.1/libfstools/mtd.c
+@@ -153,10 +153,25 @@ static int mtd_volume_find(struct volume
+ char *idx = mtd_find_index(name);
+ struct mtd_priv *p;
+ char buffer[32];
++ size_t sz;
++ FILE * fp = NULL;
+
+ if (!idx)
+ return -1;
+
++ /* if the mtd is created by block2mtd */
++ fp = fopen("/proc/cmdline", "rb");
++ if (fp) {
++ char buf[2048] = {0};
++ sz = fread(buf, 1, sizeof(buf), fp);
++ fclose(fp);
++ buf[sizeof(buf)-1] = 0;
++ if (strstr(buf, "block2mtd")) {
++ fprintf(stderr, "%s, %s is created by block2mtd.\n", __FUNCTION__, name);
++ return -1;
++ }
++ }
++
+ p = calloc(1, sizeof(struct mtd_priv));
+ if (!p)
+ return -1;
+@@ -186,12 +201,26 @@ static int mtd_volume_identify(struct vo
+ __u32 deadc0de;
+ __u16 jffs2;
+ size_t sz;
++ FILE * fp = NULL;
+
+ if (mtd_volume_load(v)) {
+ fprintf(stderr, "reading %s failed\n", v->name);
+ return -1;
+ }
+
++ /* if the mtd is created by block2mtd */
++ fp = fopen("/proc/cmdline", "rb");
++ if (fp) {
++ char buf[2048] = {0};
++ sz = fread(buf, 1, sizeof(buf), fp);
++ fclose(fp);
++ buf[sizeof(buf)-1] = 0;
++ if (strstr(buf, "block2mtd")) {
++ fprintf(stderr, "%s, %s is created by block2mtd, default use FS_EXT4.\n", __FUNCTION__, v->name);
++ return FS_EXT4;
++ }
++ }
++
+ sz = read(p->fd, &deadc0de, sizeof(deadc0de));
+
+ if (sz != sizeof(deadc0de)) {
diff --git a/package/system/fstools/patches/005-mount-options.patch b/package/system/fstools/patches/005-mount-options.patch
new file mode 100644
index 0000000..19a640c
--- /dev/null
+++ b/package/system/fstools/patches/005-mount-options.patch
@@ -0,0 +1,102 @@
+Index: fstools-2015-02-25.1/block.c
+===================================================================
+--- fstools-2015-02-25.1.orig/block.c
++++ fstools-2015-02-25.1/block.c
+@@ -541,7 +541,7 @@ static int _cache_load(const char *path)
+ static void cache_load(int mtd)
+ {
+ if (mtd) {
+- _cache_load("/dev/mtdblock*");
++ //_cache_load("/dev/mtdblock*");
+ _cache_load("/dev/ubiblock*");
+ _cache_load("/dev/ubi?*_?*");
+ }
+@@ -749,6 +749,11 @@ static int mount_device(struct blkid_str
+ if (m && m->extroot)
+ return -1;
+
++ char _data[128] = {0};
++ if (strstr(pr->id->name, "fat") || strstr(pr->id->name, "ntfs")) {
++ snprintf(_data, sizeof(_data), "%s", "iocharset=utf8,uid=65534,gid=65534");
++ }
++
+ if (m) {
+ char *target = m->target;
+ char _target[32];
+@@ -760,13 +765,15 @@ static int mount_device(struct blkid_str
+ target = _target;
+ }
+ mkdir_p(target);
++ chmod(target, 0777);
++ fprintf(stderr, "%s\n", target);
+
+ if (check_fs)
+ check_filesystem(pr);
+
+ while (1) {
+ err = mount(pr->dev, target, pr->id->name, mflags,
+- (m->options) ? (m->options) : (""));
++ (m->options) ? (m->options) : _data);
+ if (err) {
+ if (!(mflags & MS_RDONLY))
+ {
+@@ -781,6 +788,7 @@ static int mount_device(struct blkid_str
+ }
+ }
+ else {
++ chmod(target, 0777);
+ handle_swapfiles(true);
+ break;
+ }
+@@ -795,12 +803,13 @@ static int mount_device(struct blkid_str
+
+ snprintf(target, sizeof(target), "/mnt/%s", device);
+ mkdir_p(target);
++ chmod(target, 0777);
+
+ if (check_fs)
+ check_filesystem(pr);
+
+ while (1) {
+- err = mount(pr->dev, target, pr->id->name, mflags, "");
++ err = mount(pr->dev, target, pr->id->name, mflags, _data);
+ if (err) {
+ if (!(mflags & MS_RDONLY)) {
+ ERROR("Fall back on RO mount. %s.\n", strerror(errno));
+@@ -814,6 +823,7 @@ static int mount_device(struct blkid_str
+ }
+ }
+ else {
++ chmod(target, 0777);
+ handle_swapfiles(true);
+ break;
+ }
+@@ -1114,6 +1124,7 @@ static int mount_extroot(char *cfg)
+ struct blkid_struct_probe *pr;
+ struct mount *m;
+ int err = -1;
++ char _data[128];
+
+ /* Load @cfg/etc/config/fstab */
+ if (config_load(cfg))
+@@ -1141,6 +1152,11 @@ static int mount_extroot(char *cfg)
+ pr = find_block_info(m->uuid, m->label, m->device);
+ }
+ if (pr) {
++
++ if (strstr(pr->id->name, "fat") || strstr(pr->id->name, "ntfs")) {
++ snprintf(_data, sizeof(_data), "%s", "iocharset=utf8,uid=65534,gid=65534");
++ }
++
+ if (strncmp(pr->id->name, "ext", 3) &&
+ strncmp(pr->id->name, "ubifs", 5)) {
+ ERROR("extroot: unsupported filesystem %s, try ext4\n", pr->id->name);
+@@ -1159,7 +1175,7 @@ static int mount_extroot(char *cfg)
+ if (check_fs)
+ check_filesystem(pr);
+
+- err = mount(pr->dev, path, pr->id->name, 0, (m->options) ? (m->options) : (""));
++ err = mount(pr->dev, path, pr->id->name, 0, (m->options) ? (m->options) : _data);
+
+ if (err) {
+ ERROR("extroot: mounting %s (%s) on %s failed: %d (%s)\n",
diff --git a/package/system/fstools/patches/006-7623-nand.patch b/package/system/fstools/patches/006-7623-nand.patch
new file mode 100644
index 0000000..c99fc46
--- /dev/null
+++ b/package/system/fstools/patches/006-7623-nand.patch
@@ -0,0 +1,819 @@
+Index: fstools-2015-02-25.1/mount_root2.c
+===================================================================
+--- /dev/null
++++ fstools-2015-02-25.1/mount_root2.c
+@@ -0,0 +1,799 @@
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <glob.h>
++#include <dirent.h>
++#include <fcntl.h>
++#include <asm/byteorder.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/mount.h>
++
++
++#define OK (0)
++#define NG (-1)
++
++#if 0
++#define API(...) fprintf(stderr, "<api> %s\n", __FUNCTION__)
++
++#define DEBUG(...) \
++ do {\
++ fprintf(stderr, "<dbg> ");\
++ fprintf(stderr, __VA_ARGS__);\
++ fprintf(stderr, " %s, L%d.\n", __FUNCTION__, __LINE__);\
++ } while(0)
++
++
++#define DUMP_MOUNT() \
++ do { \
++ fprintf(stderr, "<<<<<<<<<< %s, L%d.\n", __FUNCTION__, __LINE__);\
++ FILE *fp = fopen("/proc/mounts", "r");\
++ static char line[256];\
++ if(!fp) break;\
++ while (fgets(line, sizeof(line), fp)) {\
++ fprintf(stderr, "%s", line);\
++ }\
++ fclose(fp);\
++ fprintf(stderr, ">>>>>>>>>> %s, L%d.\n", __FUNCTION__, __LINE__);\
++ } while(0)
++
++#define LIST_UBIDEV() do{\
++ fprintf(stderr, "<%s> L%d.", __FUNCTION__, __LINE__);\
++ system("ls -l /dev/ubi*");\
++ system("find /sys/ -name \"*ubi*\"");\
++ }while(0)
++#else
++#define API(...)
++#define DEBUG(...)
++#define DUMP_MOUNT()
++#define LIST_UBIDEV()
++#endif
++
++
++#define WAIT_UBIDEV(timeout) do{\
++ int t = timeout;\
++ while (t>=0 && access("/dev/ubi0_0", R_OK)) {\
++ fprintf(stderr, "wait for /dev/ubi0_0, %d\n", t);\
++ sleep(1); \
++ t--;\
++ }\
++ if (0 == access("/dev/ubi0_0", R_OK)) \
++ fprintf(stderr, "found /dev/ubi0_0!\n"); \
++ else\
++ fprintf(stderr, "timeout, break!\n");\
++ } while(0)
++
++
++enum
++{
++ FS_NONE, /* freash start */
++ FS_DEADCODE, /* factory reset */
++ FS_JFFS2,
++ FS_UBIFS,
++ FS_EXT4,
++};
++
++extern int pivot_root(const char *new_root, const char *put_old);
++
++static char* find_mtd_dev(char *name)
++{
++ FILE *fp = fopen("/proc/mtd", "r");
++ static char line[256] = {'/','d','e','v','/',};
++
++ if(!fp) return NULL;
++
++ while (fgets(line+5, sizeof(line)-5, fp))
++ {
++ char *ret;
++ if ((ret = strstr(line, name)) && (ret[strlen(name)] == '"'))
++ {
++ char *eol = strstr(line, ":");
++ if (!eol) continue;
++ *eol = '\0';
++ break;
++ }
++ }
++
++ fclose(fp);
++
++ return line;
++}
++
++
++static int find_filesystem(char *fs)
++{
++ FILE *fp = fopen("/proc/filesystems", "r");
++ static char line[256];
++ int ret = NG;
++
++ if (!fp)
++ {
++ DEBUG("opening /proc/filesystems failed: %s", strerror(errno));
++ goto out;
++ }
++
++ while (ret && fgets(line, sizeof(line), fp))
++ if (strstr(line, fs))
++ ret = OK;
++
++ fclose(fp);
++
++out:
++ return ret;
++}
++
++static int find_overlay_mount(char *overlay)
++{
++ FILE *fp = fopen("/proc/mounts", "r");
++ static char line[256];
++ int ret = NG;
++
++ if(!fp)
++ return ret;
++
++ while (ret && fgets(line, sizeof(line), fp))
++ if (!strncmp(line, overlay, strlen(overlay)))
++ ret = OK;
++
++ fclose(fp);
++
++ return ret;
++}
++
++static char * find_mount_point(char *block, int mtd_only)
++{
++ FILE *fp = fopen("/proc/mounts", "r");
++ static char line[256];
++ int len = strlen(block);
++ char *point = NULL;
++
++ if(!fp)
++ return NULL;
++
++ while (fgets(line, sizeof(line), fp))
++ {
++ if (!strncmp(line, block, len))
++ {
++ char *p = &line[len + 1];
++ char *t = strstr(p, " ");
++
++ if (!t)
++ {
++ fclose(fp);
++ return NULL;
++ }
++
++ *t = '\0';
++ t++;
++
++ if (mtd_only &&
++ strncmp(t, "ext4", 4) &&
++ strncmp(t, "jffs2", 5) &&
++ strncmp(t, "ubifs", 5))
++ {
++ fclose(fp);
++ DEBUG("block is mounted with wrong fs %s", t);
++ return NULL;
++ }
++ point = p;
++
++ break;
++ }
++ }
++
++ fclose(fp);
++
++ return point;
++}
++
++static void foreachdir(const char *dir, int (*cb)(const char*))
++{
++ char globdir[256];
++ glob_t gl;
++ int j;
++
++ if (dir[strlen(dir) - 1] == '/')
++ snprintf(globdir, 256, "%s*", dir);
++ else
++ snprintf(globdir, 256, "%s/*", dir);
++
++ if (!glob(globdir, GLOB_NOESCAPE | GLOB_MARK | GLOB_ONLYDIR, NULL, &gl))
++ for (j = 0; j < gl.gl_pathc; j++)
++ foreachdir(gl.gl_pathv[j], cb);
++
++ cb(dir);
++}
++
++static int handle_whiteout(const char *dir)
++{
++ struct stat s;
++ char link[256];
++ ssize_t sz;
++ struct dirent **namelist;
++ int n;
++
++ n = scandir(dir, &namelist, NULL, NULL);
++
++ if (n < 1)
++ return NG;
++
++ while (n--)
++ {
++ char file[256];
++
++ snprintf(file, sizeof(file), "%s%s", dir, namelist[n]->d_name);
++ if (!lstat(file, &s) && S_ISLNK(s.st_mode))
++ {
++ sz = readlink(file, link, sizeof(link) - 1);
++ if (sz > 0)
++ {
++ char *orig;
++
++ link[sz] = '\0';
++ orig = strstr(&file[1], "/");
++ if (orig && !strcmp(link, "(overlay-whiteout)"))
++ unlink(orig);
++ }
++ }
++ free(namelist[n]);
++ }
++ free(namelist);
++
++ return OK;
++}
++
++static int identify(char * dev)
++{
++ unsigned magic32;
++ unsigned short magic16;
++ size_t sz;
++ int fd = -1;
++ int fstype = NG; /* fs type start from 0, NG = -1. */
++
++ API();
++
++ fd = open(dev, O_RDWR | O_SYNC);
++ if (fd < 0)
++ {
++ DEBUG("open %s failed: %s", dev, strerror(errno));
++ goto __quit;
++ }
++ sz = read(fd, &magic32, sizeof(magic32));
++ if (sz != sizeof(magic32))
++ {
++ DEBUG("reading %s failed: %s", dev, strerror(errno));
++ goto __quit;
++ }
++
++ DEBUG("0x%X 0x%X 0x%X 0x%X 0x%X",
++ magic32,
++ __be32_to_cpu(magic32),
++ __be32_to_cpu(magic32) >> 16,
++ __be32_to_cpu(magic32) >> 8,
++ magic32 >> 8);
++
++ magic32 = __be32_to_cpu(magic32);
++ if (magic32 == 0xDEADC0DE)
++ {
++ DEBUG("fs is not ready - deadcode found");
++ fstype = FS_DEADCODE;
++ goto __quit;
++ }
++
++
++ if ((magic32 >> 8) == 0x554249)
++ {
++ DEBUG("ubi volume found.");
++ fstype = FS_UBIFS;
++ goto __quit;
++ }
++
++ if (__be16_to_cpu(magic32 >> 16) == 0x1985)
++ {
++ DEBUG("jffs2 is ready.");
++ fstype = FS_JFFS2;
++ goto __quit;
++ }
++
++ /* 0x400 -> super block offset in partition
++ 0x38 -> magic offset in superblock
++ */
++ lseek(fd, 0x438, SEEK_SET);
++ sz = read(fd, &magic16, sizeof(magic16));
++ if (sz != sizeof(magic16)) {
++ DEBUG("reading %s failed: %s", dev, strerror(errno));
++ goto __quit;
++ }
++
++ DEBUG("0x%X 0x%X 0x%X 0x%X",
++ magic16,
++ __be16_to_cpu(magic16),
++ __cpu_to_be16(magic16),
++ magic16 >> 8);
++
++ if (magic16 == 0xEF53) {
++ DEBUG("ext4 is ready.");
++ fstype = FS_EXT4;
++ goto __quit;
++ }
++
++ DEBUG("unable to find a supported magic number.");
++ fstype = FS_NONE;
++__quit:
++ if (fd>0) close(fd);
++ return fstype;
++}
++
++static int make_ubifs(char * dev)
++{
++ char buffer[1024];
++ API();
++ snprintf(buffer, sizeof(buffer), "ubiformat %s -y > /dev/console 2>&1", dev);
++ system(buffer);
++ DEBUG("%s, %s!", buffer, strerror(errno));
++
++ snprintf(buffer, sizeof(buffer), "ubiattach /dev/ubi_ctrl -p %s > /dev/console 2>&1", dev);
++ system(buffer);
++ DEBUG("%s, %s!", buffer, strerror(errno));
++
++ snprintf(buffer, sizeof(buffer), "ubimkvol /dev/ubi0 -s 64MiB -N rootfs_data > /dev/console 2>&1");
++ system(buffer);
++ DEBUG("%s, %s!", buffer, strerror(errno));
++
++ snprintf(buffer, sizeof(buffer), "mknod /dev/ubi0 c 246 0");
++ system(buffer);
++ DEBUG("%s, %s!", buffer, strerror(errno));
++
++ snprintf(buffer, sizeof(buffer), "mknod /dev/ubi0_0 c 246 1");
++ system(buffer);
++ DEBUG("%s, %s!", buffer, strerror(errno));
++
++ return OK;
++}
++
++static int make_jffs2(char * dev)
++{
++ API();
++ return OK;
++}
++
++static int make_ext4(char * dev)
++{
++ char buffer[128];
++ char blkdev[128];
++ API();
++
++ if (strstr(dev, "/dev/mtd") && !strstr(dev, "mtdblock"))
++ {
++ int idx = 6;
++ sscanf(dev, "/dev/mtd%d", &idx);
++ if (idx < 5)
++ {
++ DEBUG("It's dangerous to format /dev/mtd%d, give up!", idx);
++ return NG;
++ }
++ snprintf(blkdev, sizeof(blkdev), "/dev/mtdblock%d", idx);
++ DEBUG("ext4 works on block device, %s -> %s", dev, blkdev);
++ }
++ else
++ {
++ snprintf(blkdev, sizeof(blkdev), "%s", dev);
++ }
++
++ snprintf(buffer, sizeof(buffer), "mkfs.ext4 %s", blkdev);
++ system(buffer);
++ DEBUG("%s, %s!", buffer, strerror(errno));
++ return OK;
++}
++
++
++static int mount_move(char *oldroot, char *newroot, char *dir)
++{
++#ifndef MS_MOVE
++#define MS_MOVE (1 << 13)
++#endif
++ struct stat s;
++ char olddir[64];
++ char newdir[64];
++ int ret;
++
++ snprintf(olddir, sizeof(olddir), "%s%s", oldroot, dir);
++ snprintf(newdir, sizeof(newdir), "%s%s", newroot, dir);
++
++ if (stat(olddir, &s) || !S_ISDIR(s.st_mode))
++ return NG;
++
++ if (stat(newdir, &s) || !S_ISDIR(s.st_mode))
++ return NG;
++
++ ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL);
++
++/*
++ if (ret)
++ DEBUG("failed %s %s: %s", olddir, newdir, strerror(errno));
++*/
++ return ret;
++}
++
++static int pivot(char *new, char *old)
++{
++ char pivotdir[64];
++ int ret;
++
++ if (mount_move("", new, "/proc"))
++ return NG;
++
++ snprintf(pivotdir, sizeof(pivotdir), "%s%s", new, old);
++
++ /* pivot_root(new,old) moves the root file system of the calling process
++ to the directory old and makes new the new root file system of the
++ calling process. */
++ ret = pivot_root(new, pivotdir);
++
++ if (ret < 0)
++ {
++ DEBUG("pivot_root failed %s %s: %s", new, pivotdir, strerror(errno));
++ return NG;
++ }
++
++ mount_move(old, "", "/dev");
++ mount_move(old, "", "/tmp");
++ mount_move(old, "", "/sys");
++ mount_move(old, "", "/overlay");
++
++ return OK;
++}
++
++
++/* this API mount overlayfs(upper=rw_root, lower=ro_root) as root. */
++static int fopivot(char *rw_root, char *ro_root)
++{
++ char overlay[64], lowerdir[64];
++
++ if (find_filesystem("overlay"))
++ {
++ DEBUG("BUG: no suitable fs found");
++ return NG;
++ }
++
++ snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
++
++ /*
++ * First, try to mount without a workdir, for overlayfs v22 and before.
++ * If it fails, it means that we are probably using a v23 and
++ * later versions that require a workdir
++ */
++ snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s", rw_root);
++ if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir))
++ {
++ char upperdir[64], workdir[64], upgrade[64], upgrade_dest[64];
++ struct stat st;
++
++ snprintf(upperdir, sizeof(upperdir), "%s/upper", rw_root);
++ snprintf(workdir, sizeof(workdir), "%s/work", rw_root);
++ snprintf(upgrade, sizeof(upgrade), "%s/sysupgrade.tgz", rw_root);
++ snprintf(upgrade_dest, sizeof(upgrade_dest), "%s/sysupgrade.tgz", upperdir);
++ snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s,workdir=%s",
++ upperdir, workdir);
++
++ /*
++ * Overlay FS v23 and later requires both a upper and
++ * a work directory, both on the same filesystem, but
++ * not part of the same subtree.
++ * We can't really deal with these constraints without
++ * creating two new subdirectories in /overlay.
++ */
++ mkdir(upperdir, 0755);
++ mkdir(workdir, 0755);
++
++ if (stat(upgrade, &st) == 0)
++ rename(upgrade, upgrade_dest);
++
++ /* Mainlined overlayfs has been renamed to "overlay", try that first */
++ if (mount(overlay, "/mnt", "overlay", MS_NOATIME, lowerdir))
++ {
++ if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir))
++ {
++ DEBUG("mount failed: %s, options %s",
++ strerror(errno), lowerdir);
++ return NG;
++ }
++ }
++ }
++
++ return pivot("/mnt", ro_root);
++}
++
++static int ram_overlay(void)
++{
++ API();
++
++ mkdir("/tmp/root", 0755);
++ mount("tmpfs", "/tmp/root", "tmpfs", MS_NOATIME, "mode=0755");
++
++ DUMP_MOUNT();
++ fopivot("/tmp/root", "/rom");
++ DUMP_MOUNT();
++ return OK;
++}
++
++
++static int fs_overlay(int fstype, char * dev)
++{
++ char * fs = NULL;
++ char * mp = NULL;
++ int ret = NG;
++
++ API();
++
++ if (find_filesystem("overlay"))
++ {
++ DEBUG("overlayfs not enabled in kernel!");
++ return NG;
++ }
++
++ switch (fstype)
++ {
++ case FS_UBIFS:
++ WAIT_UBIDEV(10);
++ LIST_UBIDEV();
++ fs = "ubifs";
++ dev = "/dev/ubi0_0";
++ break;
++ case FS_JFFS2:
++ fs = "jffs2";
++ break;
++ case FS_EXT4:
++ fs = "ext4";
++ if (strstr(dev, "/dev/mtd") && !strstr(dev, "mtdblock"))
++ {
++ char blkdev[128];
++ int idx = 6;
++ sscanf(dev, "/dev/mtd%d", &idx);
++ if (idx < 5)
++ {
++ DEBUG("It's dangerous to format /dev/mtd%d, give up!", idx);
++ return NG;
++ }
++ snprintf(blkdev, sizeof(blkdev), "/dev/mtdblock%d", idx);
++ DEBUG("ext4 works on block device, %s -> %s", dev, blkdev);
++ dev = strdup(blkdev);
++ /* no need to free the strbuf, since the program exit soon. */
++ }
++ break;
++ default:
++ DEBUG("you are not supposed to be here!");
++ fs = "null";
++ break;
++ }
++
++ mp = find_mount_point(dev, 0);
++ if (mp && !strstr(mp, "/mnt")) /* block will mount ubifs to /mnt/ubixxx*/
++ {
++ DEBUG("rootfs_data:%s is already mounted as %s\n", dev, mp);
++ return NG;
++ }
++
++ DUMP_MOUNT();
++
++ if (find_overlay_mount("overlayfs:/tmp/root"))
++ {
++ DEBUG("overlayfs:/tmp/root not found! directly overlay fs.");
++ if (mkdir("/tmp/overlay", 0755))
++ {
++ DEBUG("mkdir /tmp/overlay: %s", strerror(errno));
++ }
++
++ if (mount(dev, "/tmp/overlay", fs, MS_NOATIME, NULL))
++ {
++ DEBUG("failed(1) to mount -t %s %s /tmp/overlay: %s. let's try again.",
++ fs, dev, strerror(errno));
++ if (mount(dev, "/tmp/overlay", fs, MS_NOATIME, NULL))
++ {
++ DEBUG("failed(2) to mount -t %s %s /tmp/overlay: %s",
++ fs, dev, strerror(errno));
++ return NG;
++ }
++ }
++
++ DEBUG("switching to overlay");
++ if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom"))
++ {
++ return NG;
++ }
++ DUMP_MOUNT();
++#if 0
++ DEBUG("doing fo cleanup");
++ umount2("/tmp/root", MNT_DETACH);
++ foreachdir("/overlay/", handle_whiteout);
++ DUMP_MOUNT();
++#endif
++
++ }
++ else
++ {
++ DEBUG("overlayfs:/tmp/root found! switch from ram_overlay to fs_overlay.");
++ if (mkdir("/rom/overlay", 0755))
++ {
++ DEBUG("mkdir /rom/overlay: %s", strerror(errno));
++ }
++
++ ret = mount(dev, "/rom/overlay", fs, MS_NOATIME, NULL);
++ if (ret)
++ {
++ DEBUG("failed - mount -t %s %s /rom/overlay: %s", fs, dev, strerror(errno));
++ return NG;
++ }
++
++ if (mount("none", "/", NULL, MS_NOATIME | MS_REMOUNT, 0))
++ {
++ DEBUG("failed - mount -o remount,ro none: %s", strerror(errno));
++ return NG;
++ }
++
++ //system("cat /tmp/root/etc/config/system > /dev/console 2>&1");
++ //system("cat /rom/overlay/etc/config/system > /dev/console 2>&1");
++ system("cp -a /tmp/root/* /rom/overlay");
++
++ if (pivot("/rom", "/mnt"))
++ {
++ DEBUG("failed - pivot /rom /mnt: %s", strerror(errno));
++ return NG;
++ }
++
++ if (mount_move("/mnt", "/tmp/root", ""))
++ {
++ DEBUG("failed - mount -o move /mnt /tmp/root %s", strerror(errno));
++ return NG;
++ }
++ fopivot("/overlay", "/rom");
++
++ DEBUG("doing fo cleanup");
++ umount2("/tmp/root", MNT_DETACH);
++ foreachdir("/overlay/", handle_whiteout);
++ }
++
++ return OK;
++}
++
++static int stage1(int argc, char *argv[1])
++{
++ char * dev = NULL;
++ int fstype = FS_NONE;
++ char tmp[64];
++
++ API();
++
++ if (!getenv("PREINIT"))
++ {
++ DEBUG("not PREINIT, skip stage1");
++ return NG;
++ }
++
++ /* check */
++ dev = find_mtd_dev("rootfs_data");
++ if (!dev)
++ {
++ DEBUG("cannot find rootfs_data");
++ return NG;
++ }
++
++ fstype = identify(dev);
++ switch(fstype)
++ {
++ case FS_UBIFS:
++ LIST_UBIDEV();
++ snprintf(tmp, sizeof(tmp), "ubiattach /dev/ubi_ctrl -p %s", dev);
++ system(tmp);
++ DEBUG("%s, %s!", tmp, strerror(errno));
++
++ snprintf(tmp, sizeof(tmp), "mknod /dev/ubi0 c 246 0");
++ system(tmp);
++ DEBUG("%s, %s!", tmp, strerror(errno));
++
++ snprintf(tmp, sizeof(tmp), "mknod /dev/ubi0_0 c 246 1");
++ system(tmp);
++ DEBUG("%s, %s!", tmp, strerror(errno));
++ LIST_UBIDEV();
++ WAIT_UBIDEV(10);
++ /* break; */
++ case FS_JFFS2:
++ /* break; */
++ case FS_EXT4:
++ #if 0
++ DEBUG("before fs_overlay, the world is like...");
++ DUMP_MOUNT();
++ system("ps w > /dev/console");
++ system("ls -l / > /dev/console");
++ system("ls -l /dev/ubi* > /dev/console");
++ #endif
++ if (OK != fs_overlay(fstype, dev))
++ {
++ DEBUG("fs_overlay failed, fallback on ram_overlay.");
++ return ram_overlay();
++ }
++ break;
++ case FS_DEADCODE:
++ /* break; */
++ case FS_NONE:
++ /* break; */
++ default:
++ DEBUG("fstype %d, go ram_overlay.", fstype);
++ return ram_overlay();
++ }
++
++ return OK;
++}
++
++
++static int stage2(int argc, char *argv[1])
++{
++ char * dev = NULL;
++ int fstype = FS_NONE;
++
++ /* check */
++ dev = find_mtd_dev("rootfs_data");
++ if (!dev)
++ {
++ DEBUG("cannot find rootfs_data");
++ return NG;
++ }
++
++ fstype = identify(dev);
++ switch(fstype)
++ {
++ case FS_UBIFS:
++ case FS_JFFS2:
++ case FS_EXT4:
++ DEBUG("job should have be done in stage1.");
++ return fs_overlay(fstype, dev);
++ case FS_DEADCODE:
++ /* break; */
++ case FS_NONE:
++ /* break; */
++ default:
++ DEBUG("no filesystem detected. create it now.");
++ if (0 == access("/proc/mt7623", R_OK))
++ {
++ if (0 == access("/proc/emmc", R_OK))
++ make_ext4(dev);
++ else
++ make_ubifs(dev);
++ }
++ else
++ {
++ make_jffs2(dev);
++ }
++ break;
++ }
++
++ fstype = identify(dev);
++ if (OK != fs_overlay(fstype, dev))
++ {
++ DEBUG("fs_overlay failed, fallback on ram_overlay.");
++ return ram_overlay();
++ }
++
++ return OK;
++}
++
++
++int main(int argc, char ** argv)
++{
++ DEBUG("mount_root2.");
++
++ if (argc < 2)
++ {
++ return stage1(argc, argv);
++ }
++
++ if (!strcmp(argv[1], "done"))
++ return stage2(argc, argv);
++ return NG;
++}
++
++
++
+Index: fstools-2015-02-25.1/CMakeLists.txt
+===================================================================
+--- fstools-2015-02-25.1.orig/CMakeLists.txt
++++ fstools-2015-02-25.1/CMakeLists.txt
+@@ -52,6 +52,10 @@ ADD_EXECUTABLE(mount_root mount_root.c)
+ TARGET_LINK_LIBRARIES(mount_root fstools)
+ INSTALL(TARGETS mount_root RUNTIME DESTINATION sbin)
+
++ADD_EXECUTABLE(mount_root2 mount_root2.c)
++TARGET_LINK_LIBRARIES(mount_root2 fstools)
++INSTALL(TARGETS mount_root2 RUNTIME DESTINATION sbin)
++
+ ADD_EXECUTABLE(block block.c)
+ IF(DEFINED CMAKE_UBIFS_EXTROOT)
+ ADD_DEFINITIONS(-DUBIFS_EXTROOT)