Procházet zdrojové kódy

Backport staged sysupgrade patches

The staged sysupgrade allows to properly unmount the rootfs before writing
the new partitions. This will fix upgrades losing configuration when
parition sizes change on x86 and similar image types.
Matthias Schiffer před 7 roky
rodič
revize
52d28c1140
18 změnil soubory, kde provedl 2487 přidání a 0 odebrání
  1. 26 0
      patches/lede/0012-procd-update-to-git-HEAD-version.patch
  2. 128 0
      patches/lede/0013-sunxi-clean-up-modules-definitions.patch
  3. 28 0
      patches/lede/0014-procd-clean-up-trailing-whitespace-in-nand.sh.patch
  4. 32 0
      patches/lede/0015-procd-prepare-NAND-sysupgrade-for-making-upgraded-dynamically-linked.patch
  5. 35 0
      patches/lede/0016-procd-update-to-latest-git-HEAD.patch
  6. 934 0
      patches/lede/0017-procd-remove-procd-nand-package.patch
  7. 476 0
      patches/lede/0018-base-files-always-use-staged-sysupgrade.patch
  8. 19 0
      patches/lede/0019-fstools-clean-up-trailing-whitespace-in-snapshot-script.patch
  9. 49 0
      patches/lede/0020-fstools-snapshot-handle-jffs2-conversion-using-upgraded.patch
  10. 258 0
      patches/lede/0021-base-files-sysupgrade-cleanup.patch
  11. 72 0
      patches/lede/0022-base-files-add-support-for-staged-sysupgrades-from-failsafe-mode.patch
  12. 35 0
      patches/lede/0023-ramips-sysupgrade-move-nand_do_upgrade-call-to-platform_do_upgrade.patch
  13. 62 0
      patches/lede/0024-x86-sysupgrade-move-partition-table-change-check-to-platform_check_image.patch
  14. 90 0
      patches/lede/0025-x86-sysupgrade-refactor-platform_do_upgrade.patch
  15. 26 0
      patches/lede/0026-x86-sysupgrade-explicitly-rescan-disk-after-writing-partition-table.patch
  16. 29 0
      patches/lede/0027-sunxi-sysupgrade-don-t-write-partitions-twice.patch
  17. 163 0
      patches/lede/0028-sunxi-sysupgrade-sync-with-x86.patch
  18. 25 0
      patches/lede/0029-procd-update-to-latest-git-HEAD.patch

+ 26 - 0
patches/lede/0012-procd-update-to-git-HEAD-version.patch

@@ -0,0 +1,26 @@
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Mon, 6 Mar 2017 17:25:44 +0100
+Subject: procd: update to git HEAD version
+
+8f218f5 procd: service gets deleted when its last instance is freed
+35209a0 procd: update modprobe path
+
+Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index fd1bca3f4b9665581f9e9ddd9b9294fa500a9d3d..43ea23aab00918a2b664e9a5da7767f90cd568db 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -12,9 +12,9 @@ PKG_RELEASE:=1
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git
+-PKG_SOURCE_DATE:=2017-02-15
+-PKG_SOURCE_VERSION:=5f9124103410c178d816bb5229fba7dd2286a49b
+-PKG_MIRROR_HASH:=ec887b349fc60ad3882fc9eaefb5cd299d64e7d43c062df9f7b7500591ba3e85
++PKG_SOURCE_DATE:=2017-03-05
++PKG_SOURCE_VERSION:=8f218f5626a3cb3900dbe9801ee8ace236b0e4a5
++PKG_MIRROR_HASH:=8ac8691888b64726453bd726fe0c98fc906540bbd2ae666dae6bea592b0b4e4d
+ CMAKE_INSTALL:=1
+ 
+ PKG_LICENSE:=GPL-2.0

+ 128 - 0
patches/lede/0013-sunxi-clean-up-modules-definitions.patch

@@ -0,0 +1,128 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Thu, 4 May 2017 07:00:06 +0200
+Subject: sunxi: clean up modules definitions
+
+Module definitions for kmod-wdt-sunxi and kmod-eeprom-sunxi are removed
+(wdt-sunxi was builtin anyways; nvmem-sunxi, which is the new name of
+eeprom-sunxi is changed to builtin). As kmod-eeprom-sunxi was specified
+in DEFAULT_PACKAGES, but not available on kernel 4.4, it was breaking the
+image builder.
+
+Support for kmod-sunxi-ir is added for kernel 4.4 (it is unclear why it
+was disable before, it builds fine with with kernel 4.4).
+
+Condtionals only relevant for pre-4.4 kernels are removed from modules.mk,
+as sunxi does't support older kernels anymore.
+
+Fixes FS#755.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/sunxi/Makefile b/target/linux/sunxi/Makefile
+index b0bc1bab398af55b77909deccd8f059e17d96e67..3c2f14b8418e1d296a239027f6fdee9b5ba8f9b2 100644
+--- a/target/linux/sunxi/Makefile
++++ b/target/linux/sunxi/Makefile
+@@ -27,7 +27,7 @@ KERNELNAME:=zImage dtbs
+ 
+ include $(INCLUDE_DIR)/target.mk
+ 
+-DEFAULT_PACKAGES += uboot-envtools kmod-eeprom-sunxi kmod-wdt-sunxi
++DEFAULT_PACKAGES += uboot-envtools
+ DEFAULT_PACKAGES += mkf2fs e2fsprogs
+ 
+ $(eval $(call BuildTarget))
+diff --git a/target/linux/sunxi/config-4.4 b/target/linux/sunxi/config-4.4
+index 2253afa124ad6c3d6b9d6798dc29f68437455341..a978e9d15b8c358f69669d3afdbf4a14bba83d31 100644
+--- a/target/linux/sunxi/config-4.4
++++ b/target/linux/sunxi/config-4.4
+@@ -356,7 +356,7 @@ CONFIG_NO_HZ_COMMON=y
+ CONFIG_NO_HZ_IDLE=y
+ CONFIG_NR_CPUS=8
+ CONFIG_NVMEM=y
+-# CONFIG_NVMEM_SUNXI_SID is not set
++CONFIG_NVMEM_SUNXI_SID=y
+ CONFIG_OF=y
+ CONFIG_OF_ADDRESS=y
+ CONFIG_OF_EARLY_FLATTREE=y
+diff --git a/target/linux/sunxi/modules.mk b/target/linux/sunxi/modules.mk
+index 6f4991798decb4a65f615d3a7282270960a7555a..99b82a3b5f17348049458ced5823f7c90f784269 100644
+--- a/target/linux/sunxi/modules.mk
++++ b/target/linux/sunxi/modules.mk
+@@ -25,7 +25,7 @@ $(eval $(call KernelPackage,rtc-sunxi))
+ define KernelPackage/sunxi-ir
+     SUBMENU:=$(OTHER_MENU)
+     TITLE:=Sunxi SoC built-in IR support (A20)
+-    DEPENDS:=@TARGET_sunxi @!LINUX_4_4 +kmod-input-core 
++    DEPENDS:=@TARGET_sunxi +kmod-input-core
+     $(call AddDepends/rtc)
+     KCONFIG:= \
+ 	CONFIG_MEDIA_SUPPORT=y \
+@@ -42,22 +42,6 @@ endef
+ 
+ $(eval $(call KernelPackage,sunxi-ir))
+ 
+-define KernelPackage/eeprom-sunxi
+-    SUBMENU:=$(OTHER_MENU)
+-    TITLE:=AllWinner Security ID fuse support
+-    DEPENDS:=@TARGET_sunxi @!LINUX_4_4
+-    KCONFIG:= \
+-	CONFIG_EEPROM_SUNXI_SID
+-    FILES:=$(LINUX_DIR)/drivers/misc/eeprom/sunxi_sid.ko
+-    AUTOLOAD:=$(call AutoLoad,50,sunxi_sid)
+-endef
+-
+-define KernelPackage/eeprom-sunxi/description
+- Support for the AllWinner Security ID fuse support
+-endef
+-
+-$(eval $(call KernelPackage,eeprom-sunxi))
+-
+ define KernelPackage/ata-sunxi
+     TITLE:=AllWinner sunXi AHCI SATA support
+     SUBMENU:=$(BLOCK_MENU)
+@@ -76,7 +60,7 @@ $(eval $(call KernelPackage,ata-sunxi))
+ define KernelPackage/sun4i-emac
+   SUBMENU:=$(NETWORK_DEVICES_MENU)
+   TITLE:=AllWinner EMAC Ethernet support
+-  DEPENDS:=@TARGET_sunxi +LINUX_4_4:kmod-of-mdio +LINUX_4_4:kmod-libphy
++  DEPENDS:=@TARGET_sunxi +kmod-of-mdio +kmod-libphy
+   KCONFIG:=CONFIG_SUN4I_EMAC
+   FILES:=$(LINUX_DIR)/drivers/net/ethernet/allwinner/sun4i-emac.ko
+   AUTOLOAD:=$(call AutoProbe,sun4i-emac)
+@@ -85,35 +69,11 @@ endef
+ $(eval $(call KernelPackage,sun4i-emac))
+ 
+ 
+-define KernelPackage/wdt-sunxi
+-    SUBMENU:=$(OTHER_MENU)
+-    TITLE:=AllWinner sunXi Watchdog timer
+-    DEPENDS:=@TARGET_sunxi
+-    KCONFIG:=CONFIG_SUNXI_WATCHDOG
+-    FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/sunxi_wdt.ko
+-    AUTOLOAD:=$(call AutoLoad,51,sunxi_wdt)
+-endef
+-
+-define KernelPackage/wdt-sunxi/description
+-    Kernel module for AllWinner sunXi watchdog timer.
+-endef
+-
+-$(eval $(call KernelPackage,wdt-sunxi))
+-
+-
+ define KernelPackage/sound-soc-sunxi
+   TITLE:=AllWinner built-in SoC sound support
+-  KCONFIG:= \
+-	CONFIG_SND_SUNXI_SOC_CODEC \
+-	CONFIG_SND_SUN4I_CODEC
+-ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),lt,4.4.0)),1)
+-  FILES+=$(LINUX_DIR)/sound/soc/sunxi/sunxi-codec.ko
+-  AUTOLOAD:=$(call AutoLoad,65,sunxi-codec)
+-endif
+-ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),ge,4.4.0)),1)
++  KCONFIG:=CONFIG_SND_SUN4I_CODEC
+   FILES:=$(LINUX_DIR)/sound/soc/sunxi/sun4i-codec.ko
+   AUTOLOAD:=$(call AutoLoad,65,sun4i-codec)
+-endif
+   DEPENDS:=@TARGET_sunxi +kmod-sound-soc-core
+   $(call AddDepends/sound)
+ endef

+ 28 - 0
patches/lede/0014-procd-clean-up-trailing-whitespace-in-nand.sh.patch

@@ -0,0 +1,28 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:27:40 +0200
+Subject: procd: clean up trailing whitespace in nand.sh
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/files/nand.sh b/package/system/procd/files/nand.sh
+index ebaaf2aa16009cc1431dbb79ba9f689c8b636069..8a164ee08537014936a8608f5a60fe0e27dcabd6 100644
+--- a/package/system/procd/files/nand.sh
++++ b/package/system/procd/files/nand.sh
+@@ -194,7 +194,7 @@ nand_upgrade_prepare_ubi() {
+ 
+ nand_do_upgrade_success() {
+ 	local conf_tar="/tmp/sysupgrade.tgz"
+-	
++
+ 	sync
+ 	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
+ 	echo "sysupgrade successful"
+@@ -231,7 +231,7 @@ nand_upgrade_ubifs() {
+ 	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
+ 
+ 	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
+-	
++
+ 	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+ 	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+ 	ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1

+ 32 - 0
patches/lede/0015-procd-prepare-NAND-sysupgrade-for-making-upgraded-dynamically-linked.patch

@@ -0,0 +1,32 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:28:05 +0200
+Subject: procd: prepare NAND sysupgrade for making upgraded dynamically linked
+
+Use install_bin to copy upgraded with all dependencies. The old name
+/tmp/upgraded is temporarily retained as a symlink to avoid breaking
+things.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/files/nand.sh b/package/system/procd/files/nand.sh
+index 8a164ee08537014936a8608f5a60fe0e27dcabd6..6bd2005344c081df20e5a330a69e49e37225c39f 100644
+--- a/package/system/procd/files/nand.sh
++++ b/package/system/procd/files/nand.sh
+@@ -333,7 +333,7 @@ nand_upgrade_stage1() {
+ 		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+ 			rm $CONF_TAR
+ 
+-		ubus call system nandupgrade "{\"path\": \"$path\" }"
++		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
+ 		exit 0
+ 	}
+ }
+@@ -370,6 +370,7 @@ nand_do_platform_check() {
+ # $(1): file to be used for upgrade
+ nand_do_upgrade() {
+ 	echo -n $1 > /tmp/sysupgrade-nand-path
+-	cp /sbin/upgraded /tmp/
++	install_bin /sbin/upgraded
++	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
+ 	nand_upgrade_stage1
+ }

+ 35 - 0
patches/lede/0016-procd-update-to-latest-git-HEAD.patch

@@ -0,0 +1,35 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Mon, 29 May 2017 23:15:22 +0200
+Subject: procd: update to latest git HEAD
+
+992b796 rcS: add missing fcntl.h include
+63789e5 init: add support for sysupgrades triggered from preinit
+5b1fb35 Remove code that has become unnecessary after sysupgrade changes
+5918b6d upgraded: add support for passing a "command" argument to stage2
+056d8dd upgraded: link dynamically, chroot during exec
+7c6cf55 system: always support staged sysupgrade
+d42b21e procd/rcS: Use /dev/null as stdin
+e0098d4 service/instance: add an auto start option
+1247db1 procd: Log initscript output prefixed with script name
+8d720b2 procd: Don't use syslog before its initialization
+2555474 procd: Add missing \n in debug message
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index 43ea23aab00918a2b664e9a5da7767f90cd568db..805583143fa865d9ffb38355f10ad300e222400e 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -12,9 +12,9 @@ PKG_RELEASE:=1
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git
+-PKG_SOURCE_DATE:=2017-03-05
+-PKG_SOURCE_VERSION:=8f218f5626a3cb3900dbe9801ee8ace236b0e4a5
+-PKG_MIRROR_HASH:=8ac8691888b64726453bd726fe0c98fc906540bbd2ae666dae6bea592b0b4e4d
++PKG_SOURCE_DATE:=2017-05-29
++PKG_SOURCE_VERSION:=992b796204caf5b0290ea4a1246b43b353b6c1d7
++PKG_MIRROR_HASH:=effecf66ef6a7396dd26d54a5d232b4a895d9fe7aaca83063aaffc7b39a051d5
+ CMAKE_INSTALL:=1
+ 
+ PKG_LICENSE:=GPL-2.0

+ 934 - 0
patches/lede/0017-procd-remove-procd-nand-package.patch

@@ -0,0 +1,934 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Fri, 21 Apr 2017 20:37:58 +0200
+Subject: procd: remove procd-nand package
+
+We always want to support staged upgrades now, so it's better to include
+upgraded into the main package. /lib/upgrade/nand.sh is moved to
+base-files.
+
+The procd-nand-firstboot package is removed for now, it may return later
+as a separate package.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/Makefile b/package/base-files/Makefile
+index 78c3dc9390cf58fde8483596563c2e6e5e500887..aeef3dbc12f0c5ffdef0e7034e5446bfe1a1c7c4 100644
+--- a/package/base-files/Makefile
++++ b/package/base-files/Makefile
+@@ -18,7 +18,9 @@ PKG_FILE_DEPENDS:=$(PLATFORM_DIR)/ $(GENERIC_PLATFORM_DIR)/base-files/
+ PKG_BUILD_DEPENDS:=usign/host
+ PKG_LICENSE:=GPL-2.0
+ 
+-PKG_CONFIG_DEPENDS := CONFIG_SIGNED_PACKAGES CONFIG_TARGET_INIT_PATH CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE
++PKG_CONFIG_DEPENDS := \
++	CONFIG_SIGNED_PACKAGES CONFIG_TARGET_INIT_PATH CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE \
++	CONFIG_NAND_SUPPORT
+ 
+ include $(INCLUDE_DIR)/package.mk
+ 
+@@ -30,7 +32,7 @@ endif
+ define Package/base-files
+   SECTION:=base
+   CATEGORY:=Base system
+-  DEPENDS:=+netifd +libc +procd +jsonfilter +SIGNED_PACKAGES:usign +SIGNED_PACKAGES:lede-keyring +fstools +fwtool
++  DEPENDS:=+netifd +libc +procd +jsonfilter +SIGNED_PACKAGES:usign +SIGNED_PACKAGES:lede-keyring +NAND_SUPPORT:ubi-utils +fstools +fwtool
+   TITLE:=Base filesystem for Lede
+   URL:=http://openwrt.org/
+   VERSION:=$(PKG_RELEASE)-$(REVISION)
+@@ -105,9 +107,16 @@ ifdef CONFIG_SIGNED_PACKAGES
+   endef
+ endif
+ 
++ifeq ($(CONFIG_NAND_SUPPORT),)
++  define Package/base-files/nand-support
++	rm -f $(1)/lib/upgrade/nand.sh
++  endef
++endif
++
+ define Package/base-files/install
+ 	$(CP) ./files/* $(1)/
+ 	$(Package/base-files/install-key)
++	$(Package/base-files/nand-support)
+ 	if [ -d $(GENERIC_PLATFORM_DIR)/base-files/. ]; then \
+ 		$(CP) $(GENERIC_PLATFORM_DIR)/base-files/* $(1)/; \
+ 	fi
+diff --git a/package/base-files/files/lib/upgrade/nand.sh b/package/base-files/files/lib/upgrade/nand.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..6bd2005344c081df20e5a330a69e49e37225c39f
+--- /dev/null
++++ b/package/base-files/files/lib/upgrade/nand.sh
+@@ -0,0 +1,376 @@
++#!/bin/sh
++# Copyright (C) 2014 OpenWrt.org
++#
++
++. /lib/functions.sh
++
++# 'kernel' partition on NAND contains the kernel
++CI_KERNPART="kernel"
++
++# 'ubi' partition on NAND contains UBI
++CI_UBIPART="ubi"
++
++ubi_mknod() {
++	local dir="$1"
++	local dev="/dev/$(basename $dir)"
++
++	[ -e "$dev" ] && return 0
++
++	local devid="$(cat $dir/dev)"
++	local major="${devid%%:*}"
++	local minor="${devid##*:}"
++	mknod "$dev" c $major $minor
++}
++
++nand_find_volume() {
++	local ubidevdir ubivoldir
++	ubidevdir="/sys/devices/virtual/ubi/$1"
++	[ ! -d "$ubidevdir" ] && return 1
++	for ubivoldir in $ubidevdir/${1}_*; do
++		[ ! -d "$ubivoldir" ] && continue
++		if [ "$( cat $ubivoldir/name )" = "$2" ]; then
++			basename $ubivoldir
++			ubi_mknod "$ubivoldir"
++			return 0
++		fi
++	done
++}
++
++nand_find_ubi() {
++	local ubidevdir ubidev mtdnum
++	mtdnum="$( find_mtd_index $1 )"
++	[ ! "$mtdnum" ] && return 1
++	for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
++		[ ! -d "$ubidevdir" ] && continue
++		cmtdnum="$( cat $ubidevdir/mtd_num )"
++		[ ! "$mtdnum" ] && continue
++		if [ "$mtdnum" = "$cmtdnum" ]; then
++			ubidev=$( basename $ubidevdir )
++			ubi_mknod "$ubidevdir"
++			echo $ubidev
++			return 0
++		fi
++	done
++}
++
++nand_get_magic_long() {
++	dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
++}
++
++get_magic_long_tar() {
++	( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
++}
++
++identify_magic() {
++	local magic=$1
++	case "$magic" in
++		"55424923")
++			echo "ubi"
++			;;
++		"31181006")
++			echo "ubifs"
++			;;
++		"68737173")
++			echo "squashfs"
++			;;
++		"d00dfeed")
++			echo "fit"
++			;;
++		"4349"*)
++			echo "combined"
++			;;
++		*)
++			echo "unknown $magic"
++			;;
++	esac
++}
++
++
++identify() {
++	identify_magic $(nand_get_magic_long "$1" "${2:-0}")
++}
++
++identify_tar() {
++	identify_magic $(get_magic_long_tar "$1" "$2")
++}
++
++nand_restore_config() {
++	sync
++	local ubidev=$( nand_find_ubi $CI_UBIPART )
++	local ubivol="$( nand_find_volume $ubidev rootfs_data )"
++	[ ! "$ubivol" ] &&
++		ubivol="$( nand_find_volume $ubidev rootfs )"
++	mkdir /tmp/new_root
++	if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
++		echo "mounting ubifs $ubivol failed"
++		rmdir /tmp/new_root
++		return 1
++	fi
++	mv "$1" "/tmp/new_root/sysupgrade.tgz"
++	umount /tmp/new_root
++	sync
++	rmdir /tmp/new_root
++}
++
++nand_upgrade_prepare_ubi() {
++	local rootfs_length="$1"
++	local rootfs_type="$2"
++	local has_kernel="${3:-0}"
++	local has_env="${4:-0}"
++
++	local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
++	if [ ! "$mtdnum" ]; then
++		echo "cannot find ubi mtd partition $CI_UBIPART"
++		return 1
++	fi
++
++	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	if [ ! "$ubidev" ]; then
++		ubiattach -m "$mtdnum"
++		sync
++		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	fi
++
++	if [ ! "$ubidev" ]; then
++		ubiformat /dev/mtd$mtdnum -y
++		ubiattach -m "$mtdnum"
++		sync
++		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++		[ "$has_env" -gt 0 ] && {
++			ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
++			ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
++		}
++	fi
++
++	local kern_ubivol="$( nand_find_volume $ubidev kernel )"
++	local root_ubivol="$( nand_find_volume $ubidev rootfs )"
++	local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
++
++	# remove ubiblock device of rootfs
++	local root_ubiblk="ubiblock${root_ubivol:3}"
++	if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then
++		echo "removing $root_ubiblk"
++		if ! ubiblock -r /dev/$root_ubivol; then
++			echo "cannot remove $root_ubiblk"
++			return 1;
++		fi
++	fi
++
++	# kill volumes
++	[ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N kernel || true
++	[ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs || true
++	[ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
++
++	# update kernel
++	if [ "$has_kernel" = "1" ]; then
++		if ! ubimkvol /dev/$ubidev -N kernel -s $kernel_length; then
++			echo "cannot create kernel volume"
++			return 1;
++		fi
++	fi
++
++	# update rootfs
++	local root_size_param
++	if [ "$rootfs_type" = "ubifs" ]; then
++		root_size_param="-m"
++	else
++		root_size_param="-s $rootfs_length"
++	fi
++	if ! ubimkvol /dev/$ubidev -N rootfs $root_size_param; then
++		echo "cannot create rootfs volume"
++		return 1;
++	fi
++
++	# create rootfs_data for non-ubifs rootfs
++	if [ "$rootfs_type" != "ubifs" ]; then
++		if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
++			echo "cannot initialize rootfs_data volume"
++			return 1
++		fi
++	fi
++	sync
++	return 0
++}
++
++nand_do_upgrade_success() {
++	local conf_tar="/tmp/sysupgrade.tgz"
++
++	sync
++	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
++	echo "sysupgrade successful"
++	umount -a
++	reboot -f
++}
++
++# Flash the UBI image to MTD partition
++nand_upgrade_ubinized() {
++	local ubi_file="$1"
++	local mtdnum="$(find_mtd_index "$CI_UBIPART")"
++
++	[ ! "$mtdnum" ] && {
++		CI_UBIPART="rootfs"
++		mtdnum="$(find_mtd_index "$CI_UBIPART")"
++	}
++
++	if [ ! "$mtdnum" ]; then
++		echo "cannot find mtd device $CI_UBIPART"
++		umount -a
++		reboot -f
++	fi
++
++	local mtddev="/dev/mtd${mtdnum}"
++	ubidetach -p "${mtddev}" || true
++	sync
++	ubiformat "${mtddev}" -y -f "${ubi_file}"
++	ubiattach -p "${mtddev}"
++	nand_do_upgrade_success
++}
++
++# Write the UBIFS image to UBI volume
++nand_upgrade_ubifs() {
++	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
++
++	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
++
++	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
++	ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
++
++	nand_do_upgrade_success
++}
++
++nand_board_name() {
++	if type 'platform_nand_board_name' >/dev/null 2>/dev/null; then
++		platform_nand_board_name
++		return
++	fi
++
++	cat /tmp/sysinfo/board_name
++}
++
++nand_upgrade_tar() {
++	local tar_file="$1"
++	local board_name="$(nand_board_name)"
++	local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
++
++	local kernel_length=`(tar xf $tar_file sysupgrade-$board_name/kernel -O | wc -c) 2> /dev/null`
++	local rootfs_length=`(tar xf $tar_file sysupgrade-$board_name/root -O | wc -c) 2> /dev/null`
++
++	local rootfs_type="$(identify_tar "$tar_file" sysupgrade-$board_name/root)"
++
++	local has_kernel=1
++	local has_env=0
++
++	[ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
++		tar xf $tar_file sysupgrade-$board_name/kernel -O | mtd write - $CI_KERNPART
++	}
++	[ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
++
++	nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
++
++	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	[ "$has_kernel" = "1" ] && {
++		local kern_ubivol="$(nand_find_volume $ubidev kernel)"
++	 	tar xf $tar_file sysupgrade-$board_name/kernel -O | \
++			ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
++	}
++
++	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
++	tar xf $tar_file sysupgrade-$board_name/root -O | \
++		ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
++
++	nand_do_upgrade_success
++}
++
++# Recognize type of passed file and start the upgrade process
++nand_do_upgrade_stage2() {
++	local file_type=$(identify $1)
++
++	if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
++		platform_nand_pre_upgrade "$1"
++	fi
++
++	[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
++
++	case "$file_type" in
++		"ubi")		nand_upgrade_ubinized $1;;
++		"ubifs")	nand_upgrade_ubifs $1;;
++		*)		nand_upgrade_tar $1;;
++	esac
++}
++
++nand_upgrade_stage2() {
++	[ $1 = "nand" ] && {
++		[ -f "$2" ] && {
++			touch /tmp/sysupgrade
++
++			killall -9 telnetd
++			killall -9 dropbear
++			killall -9 ash
++
++			kill_remaining TERM
++			sleep 3
++			kill_remaining KILL
++
++			sleep 1
++
++			if [ -n "$(rootfs_type)" ]; then
++				v "Switching to ramdisk..."
++				run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
++			else
++				nand_do_upgrade_stage2 $2
++			fi
++			return 0
++		}
++		echo "Nand upgrade failed"
++		exit 1
++	}
++}
++
++nand_upgrade_stage1() {
++	[ -f /tmp/sysupgrade-nand-path ] && {
++		path="$(cat /tmp/sysupgrade-nand-path)"
++		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
++			rm $CONF_TAR
++
++		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
++		exit 0
++	}
++}
++
++# Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
++# 3 types of files:
++# 1) UBI - should contain an ubinized image, header is checked for the proper
++#    MAGIC
++# 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
++#    header is checked for the proper MAGIC
++# 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
++#    "CONTROL" file (at this point its content isn't verified)
++#
++# You usually want to call this function in platform_check_image.
++#
++# $(1): board name, used in case of passing TAR file
++# $(2): file to be checked
++nand_do_platform_check() {
++	local board_name="$1"
++	local tar_file="$2"
++	local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
++	local file_type="$(identify $2)"
++
++	[ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && {
++		echo "Invalid sysupgrade file."
++		return 1
++	}
++
++	return 0
++}
++
++# Start NAND upgrade process
++#
++# $(1): file to be used for upgrade
++nand_do_upgrade() {
++	echo -n $1 > /tmp/sysupgrade-nand-path
++	install_bin /sbin/upgraded
++	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
++	nand_upgrade_stage1
++}
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index 805583143fa865d9ffb38355f10ad300e222400e..775b9a64e172b250b3ba27e71fbf07aff46ede14 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -22,11 +22,9 @@ PKG_LICENSE_FILES:=
+ 
+ PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+ 
+-PKG_FLAGS:=nonshared
+-
+ PKG_CONFIG_DEPENDS:= \
+ 	CONFIG_TARGET_INIT_PATH CONFIG_KERNEL_SECCOMP \
+-	CONFIG_NAND_SUPPORT CONFIG_PROCD_SHOW_BOOT CONFIG_PROCD_ZRAM_TMPFS \
++	CONFIG_PROCD_SHOW_BOOT CONFIG_PROCD_ZRAM_TMPFS \
+ 	CONFIG_KERNEL_NAMESPACES CONFIG_PACKAGE_procd-ujail CONFIG_PACKAGE_procd-seccomp
+ 
+ include $(INCLUDE_DIR)/package.mk
+@@ -42,7 +40,7 @@ TARGET_LDFLAGS += $(if $(CONFIG_USE_GLIBC),-lrt)
+ define Package/procd
+   SECTION:=base
+   CATEGORY:=Base system
+-  DEPENDS:=+ubusd +ubus +libjson-script +ubox +USE_GLIBC:librt +libubox +libubus +NAND_SUPPORT:procd-nand
++  DEPENDS:=+ubusd +ubus +libjson-script +ubox +USE_GLIBC:librt +libubox +libubus
+   TITLE:=OpenWrt system process manager
+ endef
+ 
+@@ -60,20 +58,6 @@ define Package/procd-seccomp
+   TITLE:=OpenWrt process seccomp helper + utrace
+ endef
+ 
+-define Package/procd-nand
+-  SECTION:=utils
+-  CATEGORY:=Utilities
+-  DEPENDS:=@NAND_SUPPORT +ubi-utils
+-  TITLE:=OpenWrt sysupgrade nand helper
+-endef
+-
+-define Package/procd-nand-firstboot
+-  SECTION:=utils
+-  CATEGORY:=Utilities
+-  DEPENDS:=procd-nand
+-  TITLE:=OpenWrt firstboot nand helper
+-endef
+-
+ define Package/procd/config
+ menu "Configuration"
+ 	depends on PACKAGE_procd
+@@ -91,10 +75,6 @@ endmenu
+ endef
+ 
+ 
+-ifeq ($(CONFIG_NAND_SUPPORT),y)
+-  CMAKE_OPTIONS += -DBUILD_UPGRADED=1
+-endif
+-
+ ifeq ($(CONFIG_PROCD_SHOW_BOOT),y)
+   CMAKE_OPTIONS += -DSHOW_BOOT_ON_CONSOLE=1
+ endif
+@@ -114,7 +94,7 @@ endif
+ define Package/procd/install
+ 	$(INSTALL_DIR) $(1)/sbin $(1)/etc $(1)/lib/functions
+ 
+-	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{init,procd,askfirst,udevtrigger} $(1)/sbin/
++	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{init,procd,askfirst,udevtrigger,upgraded} $(1)/sbin/
+ 	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libsetlbf.so $(1)/lib
+ 	$(INSTALL_BIN) ./files/reload_config $(1)/sbin/
+ 	$(INSTALL_DATA) ./files/hotplug*.json $(1)/etc/
+@@ -133,21 +113,6 @@ define Package/procd-seccomp/install
+ 	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libpreload-trace.so $(1)/lib
+ endef
+ 
+-define Package/procd-nand/install
+-	$(INSTALL_DIR) $(1)/sbin $(1)/lib/upgrade
+-
+-	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/upgraded $(1)/sbin/
+-	$(INSTALL_DATA) ./files/nand.sh $(1)/lib/upgrade/
+-endef
+-
+-define Package/procd-nand-firstboot/install
+-	$(INSTALL_DIR) $(1)/lib/preinit
+-
+-	$(INSTALL_DATA) ./files/nand-preinit.sh $(1)/lib/preinit/60-nand-firstboot.sh
+-endef
+-
+ $(eval $(call BuildPackage,procd))
+ $(eval $(call BuildPackage,procd-ujail))
+ $(eval $(call BuildPackage,procd-seccomp))
+-$(eval $(call BuildPackage,procd-nand))
+-$(eval $(call BuildPackage,procd-nand-firstboot))
+diff --git a/package/system/procd/files/nand-preinit.sh b/package/system/procd/files/nand-preinit.sh
+deleted file mode 100644
+index cf596246d1f2891cbeb7b5c7cac4bb6e002b13fb..0000000000000000000000000000000000000000
+--- a/package/system/procd/files/nand-preinit.sh
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#!/bin/sh
+-# Copyright (C) 2014 OpenWrt.org
+-
+-nand_takeover() {
+-	. /lib/upgrade/nand.sh
+-	mtd=$(find_mtd_index "$CI_UBIPART")
+-	esize=$(cat /proc/mtd | grep mtd$mtd |cut -d" " -f 3)
+-	[ -z "$esize" ] && return 1
+-	esize=$(printf "%d" 0x$esize)
+-	for a in `seq 0 64`; do
+-		mtd -o $((a * esize)) -l 400 dump /dev/mtd$mtd > /tmp/takeover.hdr
+-		MAGIC=$(dd if=/tmp/takeover.hdr bs=1 skip=261 count=5 2> /dev/null)
+-		SIZE=$(printf "%d" 0x$(dd if=/tmp/takeover.hdr bs=4 count=1 2> /dev/null | hexdump -v -n 4 -e '1/1 "%02x"'))
+-		[ "$MAGIC" = "ustar" ] && {
+-			mtd -o $((a * esize)) -l $((SIZE + 4)) dump /dev/mtd$mtd | dd bs=1 skip=4 of=/tmp/sysupgrade.tar
+-			nand_do_upgrade_stage2 /tmp/sysupgrade.tar
+-		}
+-	done
+-}
+-
+-boot_hook_add initramfs nand_takeover
+diff --git a/package/system/procd/files/nand.sh b/package/system/procd/files/nand.sh
+deleted file mode 100644
+index 6bd2005344c081df20e5a330a69e49e37225c39f..0000000000000000000000000000000000000000
+--- a/package/system/procd/files/nand.sh
++++ /dev/null
+@@ -1,376 +0,0 @@
+-#!/bin/sh
+-# Copyright (C) 2014 OpenWrt.org
+-#
+-
+-. /lib/functions.sh
+-
+-# 'kernel' partition on NAND contains the kernel
+-CI_KERNPART="kernel"
+-
+-# 'ubi' partition on NAND contains UBI
+-CI_UBIPART="ubi"
+-
+-ubi_mknod() {
+-	local dir="$1"
+-	local dev="/dev/$(basename $dir)"
+-
+-	[ -e "$dev" ] && return 0
+-
+-	local devid="$(cat $dir/dev)"
+-	local major="${devid%%:*}"
+-	local minor="${devid##*:}"
+-	mknod "$dev" c $major $minor
+-}
+-
+-nand_find_volume() {
+-	local ubidevdir ubivoldir
+-	ubidevdir="/sys/devices/virtual/ubi/$1"
+-	[ ! -d "$ubidevdir" ] && return 1
+-	for ubivoldir in $ubidevdir/${1}_*; do
+-		[ ! -d "$ubivoldir" ] && continue
+-		if [ "$( cat $ubivoldir/name )" = "$2" ]; then
+-			basename $ubivoldir
+-			ubi_mknod "$ubivoldir"
+-			return 0
+-		fi
+-	done
+-}
+-
+-nand_find_ubi() {
+-	local ubidevdir ubidev mtdnum
+-	mtdnum="$( find_mtd_index $1 )"
+-	[ ! "$mtdnum" ] && return 1
+-	for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
+-		[ ! -d "$ubidevdir" ] && continue
+-		cmtdnum="$( cat $ubidevdir/mtd_num )"
+-		[ ! "$mtdnum" ] && continue
+-		if [ "$mtdnum" = "$cmtdnum" ]; then
+-			ubidev=$( basename $ubidevdir )
+-			ubi_mknod "$ubidevdir"
+-			echo $ubidev
+-			return 0
+-		fi
+-	done
+-}
+-
+-nand_get_magic_long() {
+-	dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+-}
+-
+-get_magic_long_tar() {
+-	( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
+-}
+-
+-identify_magic() {
+-	local magic=$1
+-	case "$magic" in
+-		"55424923")
+-			echo "ubi"
+-			;;
+-		"31181006")
+-			echo "ubifs"
+-			;;
+-		"68737173")
+-			echo "squashfs"
+-			;;
+-		"d00dfeed")
+-			echo "fit"
+-			;;
+-		"4349"*)
+-			echo "combined"
+-			;;
+-		*)
+-			echo "unknown $magic"
+-			;;
+-	esac
+-}
+-
+-
+-identify() {
+-	identify_magic $(nand_get_magic_long "$1" "${2:-0}")
+-}
+-
+-identify_tar() {
+-	identify_magic $(get_magic_long_tar "$1" "$2")
+-}
+-
+-nand_restore_config() {
+-	sync
+-	local ubidev=$( nand_find_ubi $CI_UBIPART )
+-	local ubivol="$( nand_find_volume $ubidev rootfs_data )"
+-	[ ! "$ubivol" ] &&
+-		ubivol="$( nand_find_volume $ubidev rootfs )"
+-	mkdir /tmp/new_root
+-	if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
+-		echo "mounting ubifs $ubivol failed"
+-		rmdir /tmp/new_root
+-		return 1
+-	fi
+-	mv "$1" "/tmp/new_root/sysupgrade.tgz"
+-	umount /tmp/new_root
+-	sync
+-	rmdir /tmp/new_root
+-}
+-
+-nand_upgrade_prepare_ubi() {
+-	local rootfs_length="$1"
+-	local rootfs_type="$2"
+-	local has_kernel="${3:-0}"
+-	local has_env="${4:-0}"
+-
+-	local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
+-	if [ ! "$mtdnum" ]; then
+-		echo "cannot find ubi mtd partition $CI_UBIPART"
+-		return 1
+-	fi
+-
+-	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	if [ ! "$ubidev" ]; then
+-		ubiattach -m "$mtdnum"
+-		sync
+-		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	fi
+-
+-	if [ ! "$ubidev" ]; then
+-		ubiformat /dev/mtd$mtdnum -y
+-		ubiattach -m "$mtdnum"
+-		sync
+-		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-		[ "$has_env" -gt 0 ] && {
+-			ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
+-			ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
+-		}
+-	fi
+-
+-	local kern_ubivol="$( nand_find_volume $ubidev kernel )"
+-	local root_ubivol="$( nand_find_volume $ubidev rootfs )"
+-	local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
+-
+-	# remove ubiblock device of rootfs
+-	local root_ubiblk="ubiblock${root_ubivol:3}"
+-	if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then
+-		echo "removing $root_ubiblk"
+-		if ! ubiblock -r /dev/$root_ubivol; then
+-			echo "cannot remove $root_ubiblk"
+-			return 1;
+-		fi
+-	fi
+-
+-	# kill volumes
+-	[ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N kernel || true
+-	[ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs || true
+-	[ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
+-
+-	# update kernel
+-	if [ "$has_kernel" = "1" ]; then
+-		if ! ubimkvol /dev/$ubidev -N kernel -s $kernel_length; then
+-			echo "cannot create kernel volume"
+-			return 1;
+-		fi
+-	fi
+-
+-	# update rootfs
+-	local root_size_param
+-	if [ "$rootfs_type" = "ubifs" ]; then
+-		root_size_param="-m"
+-	else
+-		root_size_param="-s $rootfs_length"
+-	fi
+-	if ! ubimkvol /dev/$ubidev -N rootfs $root_size_param; then
+-		echo "cannot create rootfs volume"
+-		return 1;
+-	fi
+-
+-	# create rootfs_data for non-ubifs rootfs
+-	if [ "$rootfs_type" != "ubifs" ]; then
+-		if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
+-			echo "cannot initialize rootfs_data volume"
+-			return 1
+-		fi
+-	fi
+-	sync
+-	return 0
+-}
+-
+-nand_do_upgrade_success() {
+-	local conf_tar="/tmp/sysupgrade.tgz"
+-
+-	sync
+-	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
+-	echo "sysupgrade successful"
+-	umount -a
+-	reboot -f
+-}
+-
+-# Flash the UBI image to MTD partition
+-nand_upgrade_ubinized() {
+-	local ubi_file="$1"
+-	local mtdnum="$(find_mtd_index "$CI_UBIPART")"
+-
+-	[ ! "$mtdnum" ] && {
+-		CI_UBIPART="rootfs"
+-		mtdnum="$(find_mtd_index "$CI_UBIPART")"
+-	}
+-
+-	if [ ! "$mtdnum" ]; then
+-		echo "cannot find mtd device $CI_UBIPART"
+-		umount -a
+-		reboot -f
+-	fi
+-
+-	local mtddev="/dev/mtd${mtdnum}"
+-	ubidetach -p "${mtddev}" || true
+-	sync
+-	ubiformat "${mtddev}" -y -f "${ubi_file}"
+-	ubiattach -p "${mtddev}"
+-	nand_do_upgrade_success
+-}
+-
+-# Write the UBIFS image to UBI volume
+-nand_upgrade_ubifs() {
+-	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
+-
+-	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
+-
+-	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+-	ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
+-
+-	nand_do_upgrade_success
+-}
+-
+-nand_board_name() {
+-	if type 'platform_nand_board_name' >/dev/null 2>/dev/null; then
+-		platform_nand_board_name
+-		return
+-	fi
+-
+-	cat /tmp/sysinfo/board_name
+-}
+-
+-nand_upgrade_tar() {
+-	local tar_file="$1"
+-	local board_name="$(nand_board_name)"
+-	local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
+-
+-	local kernel_length=`(tar xf $tar_file sysupgrade-$board_name/kernel -O | wc -c) 2> /dev/null`
+-	local rootfs_length=`(tar xf $tar_file sysupgrade-$board_name/root -O | wc -c) 2> /dev/null`
+-
+-	local rootfs_type="$(identify_tar "$tar_file" sysupgrade-$board_name/root)"
+-
+-	local has_kernel=1
+-	local has_env=0
+-
+-	[ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
+-		tar xf $tar_file sysupgrade-$board_name/kernel -O | mtd write - $CI_KERNPART
+-	}
+-	[ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
+-
+-	nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
+-
+-	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	[ "$has_kernel" = "1" ] && {
+-		local kern_ubivol="$(nand_find_volume $ubidev kernel)"
+-	 	tar xf $tar_file sysupgrade-$board_name/kernel -O | \
+-			ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
+-	}
+-
+-	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+-	tar xf $tar_file sysupgrade-$board_name/root -O | \
+-		ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
+-
+-	nand_do_upgrade_success
+-}
+-
+-# Recognize type of passed file and start the upgrade process
+-nand_do_upgrade_stage2() {
+-	local file_type=$(identify $1)
+-
+-	if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
+-		platform_nand_pre_upgrade "$1"
+-	fi
+-
+-	[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
+-
+-	case "$file_type" in
+-		"ubi")		nand_upgrade_ubinized $1;;
+-		"ubifs")	nand_upgrade_ubifs $1;;
+-		*)		nand_upgrade_tar $1;;
+-	esac
+-}
+-
+-nand_upgrade_stage2() {
+-	[ $1 = "nand" ] && {
+-		[ -f "$2" ] && {
+-			touch /tmp/sysupgrade
+-
+-			killall -9 telnetd
+-			killall -9 dropbear
+-			killall -9 ash
+-
+-			kill_remaining TERM
+-			sleep 3
+-			kill_remaining KILL
+-
+-			sleep 1
+-
+-			if [ -n "$(rootfs_type)" ]; then
+-				v "Switching to ramdisk..."
+-				run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
+-			else
+-				nand_do_upgrade_stage2 $2
+-			fi
+-			return 0
+-		}
+-		echo "Nand upgrade failed"
+-		exit 1
+-	}
+-}
+-
+-nand_upgrade_stage1() {
+-	[ -f /tmp/sysupgrade-nand-path ] && {
+-		path="$(cat /tmp/sysupgrade-nand-path)"
+-		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+-			rm $CONF_TAR
+-
+-		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
+-		exit 0
+-	}
+-}
+-
+-# Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
+-# 3 types of files:
+-# 1) UBI - should contain an ubinized image, header is checked for the proper
+-#    MAGIC
+-# 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
+-#    header is checked for the proper MAGIC
+-# 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
+-#    "CONTROL" file (at this point its content isn't verified)
+-#
+-# You usually want to call this function in platform_check_image.
+-#
+-# $(1): board name, used in case of passing TAR file
+-# $(2): file to be checked
+-nand_do_platform_check() {
+-	local board_name="$1"
+-	local tar_file="$2"
+-	local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
+-	local file_type="$(identify $2)"
+-
+-	[ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && {
+-		echo "Invalid sysupgrade file."
+-		return 1
+-	}
+-
+-	return 0
+-}
+-
+-# Start NAND upgrade process
+-#
+-# $(1): file to be used for upgrade
+-nand_do_upgrade() {
+-	echo -n $1 > /tmp/sysupgrade-nand-path
+-	install_bin /sbin/upgraded
+-	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
+-	nand_upgrade_stage1
+-}

+ 476 - 0
patches/lede/0018-base-files-always-use-staged-sysupgrade.patch

@@ -0,0 +1,476 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 22 Apr 2017 00:54:50 +0200
+Subject: base-files: always use staged sysupgrade
+
+Support for the -d and -p options is dropped; it may be added again at some
+point by adding these flags to the ubus sysupgrade call.
+
+A downside of this is that we get a lot less information about the progress
+of the upgrade: as soon as the actual upgrade starts, all shell sessions
+are killed to allow unmounting the root filesystem.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
+index e3519ca2cb496ff0835a9ef87da7faf217a07964..17248c2b1decd6f92558fb89601238b55fd0f0d6 100644
+--- a/package/base-files/files/lib/upgrade/common.sh
++++ b/package/base-files/files/lib/upgrade/common.sh
+@@ -56,7 +56,6 @@ run_ramfs() { # <command> [...]
+ 		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
+ 		/bin/mknod
+ 
+-	install_bin /bin/uclient-fetch /bin/wget
+ 	install_bin /sbin/mtd
+ 	install_bin /sbin/mount_root
+ 	install_bin /sbin/snapshot
+@@ -96,51 +95,37 @@ run_ramfs() { # <command> [...]
+ 	exec /bin/busybox ash -c "$*"
+ }
+ 
+-kill_remaining() { # [ <signal> ]
++kill_remaining() { # [ <signal> [ <loop> ] ]
+ 	local sig="${1:-TERM}"
++	local loop="${2:-0}"
++	local run=true
++	local stat
++
+ 	echo -n "Sending $sig to remaining processes ... "
+ 
+-	local my_pid=$$
+-	local my_ppid=$(cut -d' ' -f4  /proc/$my_pid/stat)
+-	local my_ppisupgraded=
+-	grep -q upgraded /proc/$my_ppid/cmdline >/dev/null && {
+-		local my_ppisupgraded=1
+-	}
+-	
+-	local stat
+-	for stat in /proc/[0-9]*/stat; do
+-		[ -f "$stat" ] || continue
+-
+-		local pid name state ppid rest
+-		read pid name state ppid rest < $stat
+-		name="${name#(}"; name="${name%)}"
+-
+-		local cmdline
+-		read cmdline < /proc/$pid/cmdline
+-
+-		# Skip kernel threads
+-		[ -n "$cmdline" ] || continue
+-
+-		if [ $$ -eq 1 ] || [ $my_ppid -eq 1 ] && [ -n "$my_ppisupgraded" ]; then
+-			# Running as init process, kill everything except me
+-			if [ $pid -ne $$ ] && [ $pid -ne $my_ppid ]; then
+-				echo -n "$name "
+-				kill -$sig $pid 2>/dev/null
+-			fi
+-		else 
+-			case "$name" in
+-				# Skip essential services
+-				*procd*|*ash*|*init*|*watchdog*|*ssh*|*dropbear*|*telnet*|*login*|*hostapd*|*wpa_supplicant*|*nas*|*relayd*) : ;;
+-
+-				# Killable process
+-				*)
+-					if [ $pid -ne $$ ] && [ $ppid -ne $$ ]; then
+-						echo -n "$name "
+-						kill -$sig $pid 2>/dev/null
+-					fi
+-				;;
+-			esac
+-		fi
++	while $run; do
++		run=false
++		for stat in /proc/[0-9]*/stat; do
++			[ -f "$stat" ] || continue
++
++			local pid name state ppid rest
++			read pid name state ppid rest < $stat
++			name="${name#(}"; name="${name%)}"
++
++			# Skip PID1, ourself and our children
++			[ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
++
++			local cmdline
++			read cmdline < /proc/$pid/cmdline
++
++			# Skip kernel threads
++			[ -n "$cmdline" ] || continue
++
++			echo -n "$name "
++			kill -$sig $pid 2>/dev/null
++
++			[ $loop -eq 1 ] && run=true
++		done
+ 	done
+ 	echo ""
+ }
+@@ -175,28 +160,31 @@ v() {
+ 	[ "$VERBOSE" -ge 1 ] && echo "$@"
+ }
+ 
++json_string() {
++	local v="$1"
++	v="${v//\\/\\\\}"
++	v="${v//\"/\\\"}"
++	echo "\"$v\""
++}
++
+ rootfs_type() {
+ 	/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }'
+ }
+ 
+ get_image() { # <source> [ <command> ]
+ 	local from="$1"
+-	local conc="$2"
+-	local cmd
+-
+-	case "$from" in
+-		http://*|ftp://*) cmd="wget -O- -q";;
+-		*) cmd="cat";;
+-	esac
+-	if [ -z "$conc" ]; then
+-		local magic="$(eval $cmd \"$from\" 2>/dev/null | dd bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
++	local cat="$2"
++
++	if [ -z "$cat" ]; then
++		local magic="$(dd if="$from" bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
+ 		case "$magic" in
+-			1f8b) conc="zcat";;
+-			425a) conc="bzcat";;
++			1f8b) cat="zcat";;
++			425a) cat="bzcat";;
++			*) cat="cat";;
+ 		esac
+ 	fi
+ 
+-	eval "$cmd \"$from\" 2>/dev/null ${conc:+| $conc}"
++	$cat "$from" 2>/dev/null
+ }
+ 
+ get_magic_word() {
+@@ -320,12 +308,14 @@ default_do_upgrade() {
+ 	fi
+ }
+ 
+-do_upgrade() {
++do_upgrade_stage2() {
+ 	v "Performing system upgrade..."
+-	if type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
+-		platform_do_upgrade "$ARGV"
++	if [ -n "$do_upgrade" ]; then
++		$do_upgrade "$IMAGE"
++	elif type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
++		platform_do_upgrade "$IMAGE"
+ 	else
+-		default_do_upgrade "$ARGV"
++		default_do_upgrade "$IMAGE"
+ 	fi
+ 
+ 	if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
+@@ -333,12 +323,11 @@ do_upgrade() {
+ 	fi
+ 
+ 	v "Upgrade completed"
+-	[ -n "$DELAY" ] && sleep "$DELAY"
+-	ask_bool 1 "Reboot" && {
+-		v "Rebooting system..."
+-		umount -a
+-		reboot -f
+-		sleep 5
+-		echo b 2>/dev/null >/proc/sysrq-trigger
+-	}
++	sleep 1
++
++	v "Rebooting system..."
++	umount -a
++	reboot -f
++	sleep 5
++	echo b 2>/dev/null >/proc/sysrq-trigger
+ }
+diff --git a/package/base-files/files/lib/upgrade/nand.sh b/package/base-files/files/lib/upgrade/nand.sh
+index 6bd2005344c081df20e5a330a69e49e37225c39f..1e69c8f9657b39adf2a2c33bd9bac9303bcbc3d7 100644
+--- a/package/base-files/files/lib/upgrade/nand.sh
++++ b/package/base-files/files/lib/upgrade/nand.sh
+@@ -283,7 +283,16 @@ nand_upgrade_tar() {
+ }
+ 
+ # Recognize type of passed file and start the upgrade process
+-nand_do_upgrade_stage2() {
++nand_do_upgrade() {
++	if [ -n "$IS_PRE_UPGRADE" ]; then
++		# Previously, nand_do_upgrade was called from the platform_pre_upgrade
++		# hook; this piece of code handles scripts that haven't been
++		# updated. All scripts should gradually move to call nand_do_upgrade
++		# from platform_do_upgrade instead.
++		export do_upgrade=nand_do_upgrade
++		return
++	fi
++
+ 	local file_type=$(identify $1)
+ 
+ 	if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
+@@ -299,45 +308,6 @@ nand_do_upgrade_stage2() {
+ 	esac
+ }
+ 
+-nand_upgrade_stage2() {
+-	[ $1 = "nand" ] && {
+-		[ -f "$2" ] && {
+-			touch /tmp/sysupgrade
+-
+-			killall -9 telnetd
+-			killall -9 dropbear
+-			killall -9 ash
+-
+-			kill_remaining TERM
+-			sleep 3
+-			kill_remaining KILL
+-
+-			sleep 1
+-
+-			if [ -n "$(rootfs_type)" ]; then
+-				v "Switching to ramdisk..."
+-				run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
+-			else
+-				nand_do_upgrade_stage2 $2
+-			fi
+-			return 0
+-		}
+-		echo "Nand upgrade failed"
+-		exit 1
+-	}
+-}
+-
+-nand_upgrade_stage1() {
+-	[ -f /tmp/sysupgrade-nand-path ] && {
+-		path="$(cat /tmp/sysupgrade-nand-path)"
+-		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+-			rm $CONF_TAR
+-
+-		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
+-		exit 0
+-	}
+-}
+-
+ # Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
+ # 3 types of files:
+ # 1) UBI - should contain an ubinized image, header is checked for the proper
+@@ -364,13 +334,3 @@ nand_do_platform_check() {
+ 
+ 	return 0
+ }
+-
+-# Start NAND upgrade process
+-#
+-# $(1): file to be used for upgrade
+-nand_do_upgrade() {
+-	echo -n $1 > /tmp/sysupgrade-nand-path
+-	install_bin /sbin/upgraded
+-	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
+-	nand_upgrade_stage1
+-}
+diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2
+new file mode 100755
+index 0000000000000000000000000000000000000000..4e2aa3a23c3bab07a795762a30a4d4f701081934
+--- /dev/null
++++ b/package/base-files/files/lib/upgrade/stage2
+@@ -0,0 +1,50 @@
++#!/bin/sh
++
++. /lib/functions.sh
++. /lib/functions/system.sh
++
++export IMAGE="$1"
++COMMAND="$2"
++
++export ARGV="$IMAGE"
++export ARGC=1
++
++export SAVE_CONFIG=1
++export SAVE_PARTITIONS=1
++
++export INTERACTIVE=0
++export VERBOSE=1
++export CONFFILES=/tmp/sysupgrade.conffiles
++export CONF_TAR=/tmp/sysupgrade.tgz
++
++
++[ -f "$CONF_TAR" ] || export SAVE_CONFIG=0
++[ -f /tmp/sysupgrade.always.overwrite.bootdisk.partmap ] && export SAVE_PARTITIONS=0
++
++include /lib/upgrade
++
++
++killall -9 telnetd
++killall -9 dropbear
++killall -9 ash
++
++kill_remaining TERM
++sleep 3
++kill_remaining KILL 1
++
++sleep 1
++
++
++if [ -n "$IMAGE" ] && type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then
++	IS_PRE_UPGRADE=1 platform_pre_upgrade "$IMAGE"
++
++	# Needs to be unset again because of busybox weirdness ...
++	IS_PRE_UPGRADE=
++fi
++
++if [ -n "$(rootfs_type)" ]; then
++	echo "Switching to ramdisk..."
++	run_ramfs "$COMMAND"
++else
++	exec /bin/busybox ash -c "$COMMAND"
++fi
+diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
+index c095ca81c50c71021af2dc04a561ac22f6b7442b..2d67371ef74b4b970076a069e97f4fd6a1e0bc95 100755
+--- a/package/base-files/files/sbin/sysupgrade
++++ b/package/base-files/files/sbin/sysupgrade
+@@ -1,4 +1,7 @@
+ #!/bin/sh
++
++[ "$1" = "nand" ] && exec /lib/upgrade/stage2 "$2" "$3"
++
+ . /lib/functions.sh
+ . /lib/functions/system.sh
+ 
+@@ -11,7 +14,6 @@ export VERBOSE=1
+ export SAVE_CONFIG=1
+ export SAVE_OVERLAY=0
+ export SAVE_PARTITIONS=1
+-export DELAY=
+ export CONF_IMAGE=
+ export CONF_BACKUP_LIST=0
+ export CONF_BACKUP=
+@@ -25,7 +27,6 @@ export TEST=0
+ while [ -n "$1" ]; do
+ 	case "$1" in
+ 		-i) export INTERACTIVE=1;;
+-		-d) export DELAY="$2"; shift;;
+ 		-v) export VERBOSE="$(($VERBOSE + 1))";;
+ 		-q) export VERBOSE="$(($VERBOSE - 1))";;
+ 		-n) export SAVE_CONFIG=0;;
+@@ -50,10 +51,9 @@ done
+ export CONFFILES=/tmp/sysupgrade.conffiles
+ export CONF_TAR=/tmp/sysupgrade.tgz
+ 
+-export ARGV="$*"
+-export ARGC="$#"
++IMAGE="$1"
+ 
+-[ -z "$ARGV" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
++[ -z "$IMAGE" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
+ 	cat <<EOF
+ Usage: $0 [<upgrade-option>...] <image file or URL>
+        $0 [-q] [-i] <backup-command> <file>
+@@ -90,7 +90,7 @@ EOF
+ 	exit 1
+ }
+ 
+-[ -n "$ARGV" -a -n "$NEED_IMAGE" ] && {
++[ -n "$IMAGE" -a -n "$NEED_IMAGE" ] && {
+ 	cat <<-EOF
+ 		-b|--create-backup and -r|--restore-backup do not perform a firmware upgrade.
+ 		Do not specify both -b|-r and a firmware image.
+@@ -136,14 +136,13 @@ sysupgrade_pre_upgrade="fwtool_pre_upgrade"
+ 
+ include /lib/upgrade
+ 
+-[ "$1" = "nand" ] && nand_upgrade_stage2 $@
+-
+ do_save_conffiles() {
+ 	local conf_tar="${1:-$CONF_TAR}"
+ 
+ 	[ -z "$(rootfs_type)" ] && {
+ 		echo "Cannot save config while running from ramdisk."
+ 		ask_bool 0 "Abort" && exit
++		rm -f "$conf_tar"
+ 		return 0
+ 	}
+ 	run_hooks "$CONFFILES" $sysupgrade_init_conffiles
+@@ -184,8 +183,33 @@ type platform_check_image >/dev/null 2>/dev/null || {
+ 	exit 1
+ }
+ 
++case "$IMAGE" in
++	http://*)
++		wget -O/tmp/sysupgrade.img "$IMAGE"
++		IMAGE=/tmp/sysupgrade.img
++		;;
++esac
++
++IMAGE="$(readlink -f "$IMAGE")"
++
++case "$IMAGE" in
++	'')
++		echo "Image file not found."
++		exit 1
++		;;
++	/tmp/*)	;;
++	*)
++		v "Image not in /tmp, copying..."
++		cp -f "$IMAGE" /tmp/sysupgrade.img
++		IMAGE=/tmp/sysupgrade.img
++		;;
++esac
++
++export ARGV="$IMAGE"
++export ARGC=1
++
+ for check in $sysupgrade_image_check; do
+-	( eval "$check \"\$ARGV\"" ) || {
++	( $check "$IMAGE" ) || {
+ 		if [ $FORCE -eq 1 ]; then
+ 			echo "Image check '$check' failed but --force given - will update anyway!"
+ 			break
+@@ -211,6 +235,7 @@ elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
+ 	[ $TEST -eq 1 ] || do_save_conffiles
+ 	export SAVE_CONFIG=1
+ else
++	[ $TEST -eq 1 ] || rm -f "$CONF_TAR"
+ 	export SAVE_CONFIG=0
+ fi
+ 
+@@ -218,28 +243,18 @@ if [ $TEST -eq 1 ]; then
+ 	exit 0
+ fi
+ 
+-run_hooks "" $sysupgrade_pre_upgrade
+-
+-# Some platforms/devices may want different sysupgrade process, e.g. without
+-# killing processes yet or calling ubus system upgrade method.
+-# This is needed e.g. on NAND devices where we just want to trigger stage1 at
+-# this point.
+-if type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then
+-	platform_pre_upgrade "$ARGV"
++if [ $SAVE_PARTITIONS -eq 0 ]; then
++	touch /tmp/sysupgrade.always.overwrite.bootdisk.partmap
++else
++	rm -f /tmp/sysupgrade.always.overwrite.bootdisk.partmap
+ fi
+ 
+-ubus call system upgrade
+-touch /tmp/sysupgrade
+-
+-if [ ! -f /tmp/failsafe ] ; then
+-	kill_remaining TERM
+-	sleep 3
+-	kill_remaining KILL
+-fi
++run_hooks "" $sysupgrade_pre_upgrade
+ 
+-if [ -n "$(rootfs_type)" ]; then
+-	v "Switching to ramdisk..."
+-	run_ramfs '. /lib/functions.sh; include /lib/upgrade; do_upgrade'
+-else
+-	do_upgrade
+-fi
++install_bin /sbin/upgraded
++v "Commencing upgrade. All shell sessions will be closed now."
++ubus call system sysupgrade "{
++	\"prefix\": \"$RAM_ROOT\",
++	\"path\": $(json_string "$IMAGE"),
++	\"command\": \". /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2\"
++}"

+ 19 - 0
patches/lede/0019-fstools-clean-up-trailing-whitespace-in-snapshot-script.patch

@@ -0,0 +1,19 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:29:24 +0200
+Subject: fstools: clean up trailing whitespace in snapshot script
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/fstools/files/snapshot b/package/system/fstools/files/snapshot
+index c1a5b733f3c70e2bb5f2e83d3589e2f10832760f..baf24f1e3e90fe7708e0f28c17ba270a35a2cd52 100644
+--- a/package/system/fstools/files/snapshot
++++ b/package/system/fstools/files/snapshot
+@@ -42,7 +42,7 @@ do_snapshot_upgrade() {
+ 
+ 	opkg list-upgradable
+ 	[ $? -eq 0 ] || exit 2
+-	
++
+ 	UPDATES=`opkg list-upgradable | cut -d" " -f1`
+ 	[ -z "${UPDATES}" ] && exit 0
+ 

+ 49 - 0
patches/lede/0020-fstools-snapshot-handle-jffs2-conversion-using-upgraded.patch

@@ -0,0 +1,49 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:29:55 +0200
+Subject: fstools: snapshot: handle jffs2 conversion using upgraded
+
+We can reuse the kill_remaining and run_ramfs facilities of the stage2 run
+by upgraded.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile
+index 28f68b57d6f82dd066410a577e84e32a3a54dc37..2789424c5f5fb50cc1f004d2ab5223a7fecbf53a 100644
+--- a/package/system/fstools/Makefile
++++ b/package/system/fstools/Makefile
+@@ -8,7 +8,7 @@
+ include $(TOPDIR)/rules.mk
+ 
+ PKG_NAME:=fstools
+-PKG_RELEASE:=1
++PKG_RELEASE:=2
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/fstools.git
+diff --git a/package/system/fstools/files/snapshot b/package/system/fstools/files/snapshot
+index baf24f1e3e90fe7708e0f28c17ba270a35a2cd52..a495e3434523b7a4b1b2f1bc3f4c9298197fc745 100644
+--- a/package/system/fstools/files/snapshot
++++ b/package/system/fstools/files/snapshot
+@@ -64,14 +64,16 @@ do_convert_jffs2() {
+ do_convert() {
+ 	. /lib/functions.sh
+ 	. /lib/upgrade/common.sh
+-	ubus call system upgrade
+-	touch /tmp/sysupgrade
++
+ 	cd /overlay/upper
+ 	tar czf /tmp/snapshot.tar.gz *
+-	kill_remaining TERM
+-	sleep 3
+-	kill_remaining KILL
+-	run_ramfs '. /sbin/snapshot; do_convert_jffs2'
++
++	install_bin /sbin/upgraded
++	ubus call system sysupgrade "{
++		\"prefix\": \"$RAM_ROOT\",
++		\"path\": \"\",
++		\"command\": \". /sbin/snapshot; do_convert_jffs2\"
++	}"
+ }
+ 
+ [ -n "$(cat /proc/mounts|grep /overlay|grep jffs2)" ] && {

+ 258 - 0
patches/lede/0021-base-files-sysupgrade-cleanup.patch

@@ -0,0 +1,258 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 23 Apr 2017 23:33:14 +0200
+Subject: base-files: sysupgrade cleanup
+
+Some functions only used by stage2 are moved there from common.sh.
+
+One piece that could still use more cleanup is platform_pre_upgrade: many
+targets reference files from there are aren't available in the ramfs, so
+we need to evaluate it before the switch; conversely, flash writes happen
+in that function on some targets. Targets that do the latter should be
+fixed eventually to use platform_do_upgrade for that purpose.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
+index 17248c2b1decd6f92558fb89601238b55fd0f0d6..fc59bf2323498d332159b00eb7ab443bfe6b147e 100644
+--- a/package/base-files/files/lib/upgrade/common.sh
++++ b/package/base-files/files/lib/upgrade/common.sh
+@@ -30,106 +30,6 @@ install_bin() { # <file> [ <symlink> ... ]
+ 	}; done
+ }
+ 
+-supivot() { # <new_root> <old_root>
+-	/bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1
+-	mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \
+-	/bin/mount -o noatime,move /proc $1/proc && \
+-	pivot_root $1 $1$2 || {
+-		/bin/umount -l $1 $1
+-		return 1
+-	}
+-
+-	/bin/mount -o noatime,move $2/sys /sys
+-	/bin/mount -o noatime,move $2/dev /dev
+-	/bin/mount -o noatime,move $2/tmp /tmp
+-	/bin/mount -o noatime,move $2/overlay /overlay 2>&-
+-	return 0
+-}
+-
+-run_ramfs() { # <command> [...]
+-	install_bin /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount	\
+-		/sbin/pivot_root /sbin/reboot /bin/sync /bin/dd	/bin/grep       \
+-		/bin/cp /bin/mv /bin/tar /usr/bin/md5sum "/usr/bin/[" /bin/dd	\
+-		/bin/vi /bin/ls /bin/cat /usr/bin/awk /usr/bin/hexdump		\
+-		/bin/sleep /bin/zcat /usr/bin/bzcat /usr/bin/printf /usr/bin/wc \
+-		/bin/cut /usr/bin/printf /bin/sync /bin/mkdir /bin/rmdir	\
+-		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
+-		/bin/mknod
+-
+-	install_bin /sbin/mtd
+-	install_bin /sbin/mount_root
+-	install_bin /sbin/snapshot
+-	install_bin /sbin/snapshot_tool
+-	install_bin /usr/sbin/ubiupdatevol
+-	install_bin /usr/sbin/ubiattach
+-	install_bin /usr/sbin/ubiblock
+-	install_bin /usr/sbin/ubiformat
+-	install_bin /usr/sbin/ubidetach
+-	install_bin /usr/sbin/ubirsvol
+-	install_bin /usr/sbin/ubirmvol
+-	install_bin /usr/sbin/ubimkvol
+-	install_bin /usr/sbin/partx
+-	install_bin /usr/sbin/losetup
+-	install_bin /usr/sbin/mkfs.ext4
+-	for file in $RAMFS_COPY_BIN; do
+-		install_bin ${file//:/ }
+-	done
+-	install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh $RAMFS_COPY_DATA
+-
+-	[ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64
+-
+-	supivot $RAM_ROOT /mnt || {
+-		echo "Failed to switch over to ramfs. Please reboot."
+-		exit 1
+-	}
+-
+-	/bin/mount -o remount,ro /mnt
+-	/bin/umount -l /mnt
+-
+-	grep /overlay /proc/mounts > /dev/null && {
+-		/bin/mount -o noatime,remount,ro /overlay
+-		/bin/umount -l /overlay
+-	}
+-
+-	# spawn a new shell from ramdisk to reduce the probability of cache issues
+-	exec /bin/busybox ash -c "$*"
+-}
+-
+-kill_remaining() { # [ <signal> [ <loop> ] ]
+-	local sig="${1:-TERM}"
+-	local loop="${2:-0}"
+-	local run=true
+-	local stat
+-
+-	echo -n "Sending $sig to remaining processes ... "
+-
+-	while $run; do
+-		run=false
+-		for stat in /proc/[0-9]*/stat; do
+-			[ -f "$stat" ] || continue
+-
+-			local pid name state ppid rest
+-			read pid name state ppid rest < $stat
+-			name="${name#(}"; name="${name%)}"
+-
+-			# Skip PID1, ourself and our children
+-			[ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
+-
+-			local cmdline
+-			read cmdline < /proc/$pid/cmdline
+-
+-			# Skip kernel threads
+-			[ -n "$cmdline" ] || continue
+-
+-			echo -n "$name "
+-			kill -$sig $pid 2>/dev/null
+-
+-			[ $loop -eq 1 ] && run=true
+-		done
+-	done
+-	echo ""
+-}
+-
+ run_hooks() {
+ 	local arg="$1"; shift
+ 	for func in "$@"; do
+diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2
+index 4e2aa3a23c3bab07a795762a30a4d4f701081934..cc8047d988e39ca9ba27d2588744aad469d1d978 100755
+--- a/package/base-files/files/lib/upgrade/stage2
++++ b/package/base-files/files/lib/upgrade/stage2
+@@ -24,6 +24,104 @@ export CONF_TAR=/tmp/sysupgrade.tgz
+ include /lib/upgrade
+ 
+ 
++supivot() { # <new_root> <old_root>
++	/bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1
++	mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \
++	/bin/mount -o noatime,move /proc $1/proc && \
++	pivot_root $1 $1$2 || {
++		/bin/umount -l $1 $1
++		return 1
++	}
++
++	/bin/mount -o noatime,move $2/sys /sys
++	/bin/mount -o noatime,move $2/dev /dev
++	/bin/mount -o noatime,move $2/tmp /tmp
++	/bin/mount -o noatime,move $2/overlay /overlay 2>&-
++	return 0
++}
++
++switch_to_ramfs() {
++	install_bin /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount	\
++		/sbin/pivot_root /sbin/reboot /bin/sync /bin/dd	/bin/grep       \
++		/bin/cp /bin/mv /bin/tar /usr/bin/md5sum "/usr/bin/[" /bin/dd	\
++		/bin/vi /bin/ls /bin/cat /usr/bin/awk /usr/bin/hexdump		\
++		/bin/sleep /bin/zcat /usr/bin/bzcat /usr/bin/printf /usr/bin/wc \
++		/bin/cut /usr/bin/printf /bin/sync /bin/mkdir /bin/rmdir	\
++		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
++		/bin/mknod
++
++	install_bin /sbin/mtd
++	install_bin /sbin/mount_root
++	install_bin /sbin/snapshot
++	install_bin /sbin/snapshot_tool
++	install_bin /usr/sbin/ubiupdatevol
++	install_bin /usr/sbin/ubiattach
++	install_bin /usr/sbin/ubiblock
++	install_bin /usr/sbin/ubiformat
++	install_bin /usr/sbin/ubidetach
++	install_bin /usr/sbin/ubirsvol
++	install_bin /usr/sbin/ubirmvol
++	install_bin /usr/sbin/ubimkvol
++	install_bin /usr/sbin/partx
++	install_bin /usr/sbin/losetup
++	install_bin /usr/sbin/mkfs.ext4
++	for file in $RAMFS_COPY_BIN; do
++		install_bin ${file//:/ }
++	done
++	install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh $RAMFS_COPY_DATA
++
++	[ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64
++
++	supivot $RAM_ROOT /mnt || {
++		echo "Failed to switch over to ramfs. Please reboot."
++		exit 1
++	}
++
++	/bin/mount -o remount,ro /mnt
++	/bin/umount -l /mnt
++
++	grep /overlay /proc/mounts > /dev/null && {
++		/bin/mount -o noatime,remount,ro /overlay
++		/bin/umount -l /overlay
++	}
++}
++
++kill_remaining() { # [ <signal> [ <loop> ] ]
++	local sig="${1:-TERM}"
++	local loop="${2:-0}"
++	local run=true
++	local stat
++
++	echo -n "Sending $sig to remaining processes ... "
++
++	while $run; do
++		run=false
++		for stat in /proc/[0-9]*/stat; do
++			[ -f "$stat" ] || continue
++
++			local pid name state ppid rest
++			read pid name state ppid rest < $stat
++			name="${name#(}"; name="${name%)}"
++
++			# Skip PID1, ourself and our children
++			[ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
++
++			local cmdline
++			read cmdline < /proc/$pid/cmdline
++
++			# Skip kernel threads
++			[ -n "$cmdline" ] || continue
++
++			echo -n "$name "
++			kill -$sig $pid 2>/dev/null
++
++			[ $loop -eq 1 ] && run=true
++		done
++	done
++	echo ""
++}
++
++
+ killall -9 telnetd
+ killall -9 dropbear
+ killall -9 ash
+@@ -44,7 +142,8 @@ fi
+ 
+ if [ -n "$(rootfs_type)" ]; then
+ 	echo "Switching to ramdisk..."
+-	run_ramfs "$COMMAND"
+-else
+-	exec /bin/busybox ash -c "$COMMAND"
++	switch_to_ramfs
+ fi
++
++# Exec new shell from ramfs
++exec /bin/busybox ash -c "$COMMAND"
+diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
+index 2d67371ef74b4b970076a069e97f4fd6a1e0bc95..200a0e520b5df8bcc208f4d8fd731756e94294fb 100755
+--- a/package/base-files/files/sbin/sysupgrade
++++ b/package/base-files/files/sbin/sysupgrade
+@@ -1,7 +1,5 @@
+ #!/bin/sh
+ 
+-[ "$1" = "nand" ] && exec /lib/upgrade/stage2 "$2" "$3"
+-
+ . /lib/functions.sh
+ . /lib/functions/system.sh
+ 

+ 72 - 0
patches/lede/0022-base-files-add-support-for-staged-sysupgrades-from-failsafe-mode.patch

@@ -0,0 +1,72 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Mon, 24 Apr 2017 01:31:04 +0200
+Subject: base-files: add support for staged sysupgrades from failsafe mode
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/files/lib/preinit/40_run_failsafe_hook b/package/base-files/files/lib/preinit/40_run_failsafe_hook
+index 7301f77349a1a1e42fcef9bcbc927ef55c83b991..533b0a9771e1aac603f00ecf7a4622ea9fee969d 100644
+--- a/package/base-files/files/lib/preinit/40_run_failsafe_hook
++++ b/package/base-files/files/lib/preinit/40_run_failsafe_hook
+@@ -5,8 +5,12 @@
+ run_failsafe_hook() {
+     [ "$pi_preinit_no_failsafe" = "y" ] && return
+     if [ "$FAILSAFE" = "true" ]; then
++	lock /tmp/.failsafe
+ 	boot_run_hook failsafe
+-	lock -w /tmp/.failsafe
++	while [ ! -e /tmp/sysupgrade ]; do
++	    lock -w /tmp/.failsafe
++	done
++	exit
+     fi
+ }
+ 
+diff --git a/package/base-files/files/lib/preinit/99_10_failsafe_login b/package/base-files/files/lib/preinit/99_10_failsafe_login
+index 3147cdc5a68a69cef6b1af6618a4e2367a143c2c..728c63b2e8aebf970cd7dff0d15518ccda83029c 100644
+--- a/package/base-files/files/lib/preinit/99_10_failsafe_login
++++ b/package/base-files/files/lib/preinit/99_10_failsafe_login
+@@ -8,10 +8,13 @@ failsafe_netlogin () {
+ }
+ 
+ failsafe_shell() {
+-	lock /tmp/.failsafe
+-	ash --login
+-	echo "Please reboot system when done with failsafe network logins"
+-	while true; do sleep 1; done
++	local console="$(sed -e 's/ /\n/g' /proc/cmdline | grep '^console=' | head -1 | sed -e 's/^console=//' -e 's/,.*//')"
++	[ -n "$console" ] || console=console
++	[ -c "/dev/$console" ] || return 0
++	while true; do
++		ash --login <"/dev/$console" >"/dev/$console" 2>"/dev/$console"
++		sleep 1
++	done &
+ }
+ 
+ boot_hook_add failsafe failsafe_netlogin
+diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
+index 200a0e520b5df8bcc208f4d8fd731756e94294fb..809e789f9f436aaeb47a906d46c94d5952583e5a 100755
+--- a/package/base-files/files/sbin/sysupgrade
++++ b/package/base-files/files/sbin/sysupgrade
+@@ -251,8 +251,16 @@ run_hooks "" $sysupgrade_pre_upgrade
+ 
+ install_bin /sbin/upgraded
+ v "Commencing upgrade. All shell sessions will be closed now."
+-ubus call system sysupgrade "{
+-	\"prefix\": \"$RAM_ROOT\",
+-	\"path\": $(json_string "$IMAGE"),
+-	\"command\": \". /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2\"
+-}"
++
++COMMAND='. /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2'
++
++if [ -n "$FAILSAFE" ]; then
++	printf '%s\x00%s\x00%s' "$RAM_ROOT" "$IMAGE" "$COMMAND" >/tmp/sysupgrade
++	lock -u /tmp/.failsafe
++else
++	ubus call system sysupgrade "{
++		\"prefix\": $(json_string "$RAM_ROOT"),
++		\"path\": $(json_string "$IMAGE"),
++		\"command\": $(json_string "$COMMAND")
++	}"
++fi

+ 35 - 0
patches/lede/0023-ramips-sysupgrade-move-nand_do_upgrade-call-to-platform_do_upgrade.patch

@@ -0,0 +1,35 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 22 Apr 2017 21:27:04 +0200
+Subject: ramips: sysupgrade: move nand_do_upgrade call to platform_do_upgrade
+
+All targets with NAND support should gradually move their nand_do_upgrade
+calls from platform_pre_upgrade to platform_do_upgrade.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/ramips/base-files/lib/upgrade/platform.sh b/target/linux/ramips/base-files/lib/upgrade/platform.sh
+index 7f5b1dd070b1bfe0b86b093a55165b5a139eb37c..a5cca2080d3b96cef92286b1b15f4f8832d9f8c5 100755
+--- a/target/linux/ramips/base-files/lib/upgrade/platform.sh
++++ b/target/linux/ramips/base-files/lib/upgrade/platform.sh
+@@ -254,20 +254,13 @@ platform_nand_pre_upgrade() {
+ 	esac
+ }
+ 
+-platform_pre_upgrade() {
++platform_do_upgrade() {
+ 	local board=$(ramips_board_name)
+ 
+ 	case "$board" in
+     	ubnt-erx)
+ 		nand_do_upgrade "$ARGV"
+ 		;;
+-	esac
+-}
+-
+-platform_do_upgrade() {
+-	local board=$(ramips_board_name)
+-
+-	case "$board" in
+ 	*)
+ 		default_do_upgrade "$ARGV"
+ 		;;

+ 62 - 0
patches/lede/0024-x86-sysupgrade-move-partition-table-change-check-to-platform_check_image.patch

@@ -0,0 +1,62 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:57:29 +0200
+Subject: x86: sysupgrade: move partition table change check to platform_check_image
+
+The staged sysupgrade will prevent us from using ask_bool in
+platform_do_upgrade; therefore, the check is moved to platform_check_image.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index d3e9f360aadedad0995da55205364940c9884ba4..81b349a81816033eef9df464b2a70fdb998e5a1d 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -1,13 +1,37 @@
+ platform_check_image() {
++	local diskdev partdev diff
+ 	[ "$#" -gt 1 ] && return 1
+ 
+ 	case "$(get_magic_word "$1")" in
+-		eb48|eb63) return 0;;
++		eb48|eb63) ;;
+ 		*)
+ 			echo "Invalid image type"
+ 			return 1
+ 		;;
+ 	esac
++
++	export_bootdevice && export_partdevice diskdev 0 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	get_partitions "/dev/$diskdev" bootdisk
++
++	#extract the boot sector from the image
++	get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null
++
++	get_partitions /tmp/image.bs image
++
++	#compare tables
++	diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++
++	rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image
++
++	if [ -n "$diff" ]; then
++		echo "Partition layout has changed. Full image will be written."
++		ask_bool 0 "Abort" && exit 1
++		return 0
++	fi
+ }
+ 
+ platform_copy_config() {
+@@ -36,9 +60,6 @@ platform_do_upgrade() {
+ 			#compare tables
+ 			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+ 			if [ -n "$diff" ]; then
+-				echo "Partition layout is changed.  Full image will be written."
+-				ask_bool 0 "Abort" && exit
+-
+ 				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+ 				return 0
+ 			fi

+ 90 - 0
patches/lede/0025-x86-sysupgrade-refactor-platform_do_upgrade.patch

@@ -0,0 +1,90 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 09:05:25 +0200
+Subject: x86: sysupgrade: refactor platform_do_upgrade
+
+By returning early when no upgrade device can be found and handling the
+SAVE_PARTITIONS=0 case differently, we can get rid of two levels of if.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index 81b349a81816033eef9df464b2a70fdb998e5a1d..4fa71999be7be3972676a1019488972dccd57fa2 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -47,40 +47,43 @@ platform_copy_config() {
+ platform_do_upgrade() {
+ 	local diskdev partdev diff
+ 
+-	if export_bootdevice && export_partdevice diskdev 0; then
+-		sync
+-		if [ "$SAVE_PARTITIONS" = "1" ]; then
+-			get_partitions "/dev/$diskdev" bootdisk
+-
+-			#extract the boot sector from the image
+-			get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
+-
+-			get_partitions /tmp/image.bs image
+-
+-			#compare tables
+-			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+-			if [ -n "$diff" ]; then
+-				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+-				return 0
+-			fi
+-
+-			#iterate over each partition from the image and write it to the boot disk
+-			while read part start size; do
+-				if export_partdevice partdev $part; then
+-					echo "Writing image to /dev/$partdev..."
+-					get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
+-				else
+-					echo "Unable to find partition $part device, skipped."
+-				fi
+-			done < /tmp/partmap.image
+-
+-			#copy partition uuid
+-			echo "Writing new UUID to /dev/$diskdev..."
+-			get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
++	export_bootdevice && export_partdevice diskdev 0 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	sync
++
++	if [ "$SAVE_PARTITIONS" = "1" ]; then
++		get_partitions "/dev/$diskdev" bootdisk
++
++		#extract the boot sector from the image
++		get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
++
++		get_partitions /tmp/image.bs image
++
++		#compare tables
++		diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++	else
++		diff=1
++	fi
++
++	if [ -n "$diff" ]; then
++		get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++		return 0
++	fi
++
++	#iterate over each partition from the image and write it to the boot disk
++	while read part start size; do
++		if export_partdevice partdev $part; then
++			echo "Writing image to /dev/$partdev..."
++			get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
+ 		else
+-			get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++			echo "Unable to find partition $part device, skipped."
+ 		fi
++	done < /tmp/partmap.image
+ 
+-		sleep 1
+-	fi
++	#copy partition uuid
++	echo "Writing new UUID to /dev/$diskdev..."
++	get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
+ }

+ 26 - 0
patches/lede/0026-x86-sysupgrade-explicitly-rescan-disk-after-writing-partition-table.patch

@@ -0,0 +1,26 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 09:08:29 +0200
+Subject: x86: sysupgrade: explicitly rescan disk after writing partition table
+
+This should ensure that the kernel partition can be mounted in
+platform_copy_config when its size has changed.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index 4fa71999be7be3972676a1019488972dccd57fa2..439ba8f5125d97932248ff966340165a84e1b24a 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -70,6 +70,12 @@ platform_do_upgrade() {
+ 
+ 	if [ -n "$diff" ]; then
+ 		get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++
++		# Separate removal and addtion is necessary; otherwise, partition 1
++		# will be missing if it overlaps with the old partition 2
++		partx -d - "/dev/$diskdev"
++		partx -a - "/dev/$diskdev"
++
+ 		return 0
+ 	fi
+ 

+ 29 - 0
patches/lede/0027-sunxi-sysupgrade-don-t-write-partitions-twice.patch

@@ -0,0 +1,29 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Thu, 4 May 2017 07:29:58 +0200
+Subject: sunxi: sysupgrade: don't write partitions twice
+
+When existing partitions are retained, the dd call writing the uboot image
+in the space before the first partition was accidentally writing the whole
+image, making the code for individual partitions redundant. Limit the copy
+to 1016KiB (the first 8KiB are skipped, and the first partition starts at
+1024KiB).
+
+In addition, conv=notrunc is replaced with conv=fsync. It seems this was an
+oversight, as notrunc doesn't make sense for block devices and all other dd
+commands use conv=fsync.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/sunxi/base-files/lib/upgrade/platform.sh b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+index f2cd970d428a780d7497d8802765c656a47ff421..776bdf53bf89c5eafc24b7b59b943e12f3fab77e 100644
+--- a/target/linux/sunxi/base-files/lib/upgrade/platform.sh
++++ b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+@@ -43,7 +43,7 @@ platform_do_upgrade() {
+ 			fi
+ 
+ 			#write uboot image
+-			get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 conv=notrunc
++			get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 count=1016 conv=fsync
+ 			#iterate over each partition from the image and write it to the boot disk
+ 			while read part start size; do
+ 				part="$(($part - 2))"

+ 163 - 0
patches/lede/0028-sunxi-sysupgrade-sync-with-x86.patch

@@ -0,0 +1,163 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Thu, 4 May 2017 07:39:20 +0200
+Subject: sunxi: sysupgrade: sync with x86
+
+sunxi sysupgrade was based on the x86 implementation; sync fixes and other
+changes from the current x86 version:
+
+x86: fix sysupgrades on disks with 4k block size
+x86: sysupgrade: move partition table change check to platform_check_image
+x86: sysupgrade: refactor platform_do_upgrade
+x86: sysupgrade: explicitly rescan disk after writing partition table
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/sunxi/Makefile b/target/linux/sunxi/Makefile
+index 3c2f14b8418e1d296a239027f6fdee9b5ba8f9b2..f8b8aa750a7145c9954df5a5a6a2e85f2610a72f 100644
+--- a/target/linux/sunxi/Makefile
++++ b/target/linux/sunxi/Makefile
+@@ -28,6 +28,6 @@ KERNELNAME:=zImage dtbs
+ include $(INCLUDE_DIR)/target.mk
+ 
+ DEFAULT_PACKAGES += uboot-envtools
+-DEFAULT_PACKAGES += mkf2fs e2fsprogs
++DEFAULT_PACKAGES += partx-utils mkf2fs e2fsprogs
+ 
+ $(eval $(call BuildTarget))
+diff --git a/target/linux/sunxi/base-files/lib/upgrade/platform.sh b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+index 776bdf53bf89c5eafc24b7b59b943e12f3fab77e..88ef4790e9c1452f8ce57fe1c265ce47810830ee 100644
+--- a/target/linux/sunxi/base-files/lib/upgrade/platform.sh
++++ b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+@@ -1,5 +1,28 @@
+ platform_check_image() {
+-	true
++	local diskdev partdev diff
++
++	export_bootdevice && export_partdevice diskdev -2 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	get_partitions "/dev/$diskdev" bootdisk
++
++	#extract the boot sector from the image
++	get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null
++
++	get_partitions /tmp/image.bs image
++
++	#compare tables
++	diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++
++	rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image
++
++	if [ -n "$diff" ]; then
++		echo "Partition layout has changed. Full image will be written."
++		ask_bool 0 "Abort" && exit 1
++		return 0
++	fi
+ }
+ 
+ platform_copy_config() {
+@@ -13,55 +36,54 @@ platform_copy_config() {
+ }
+ 
+ platform_do_upgrade() {
+-	local diskdev partdev ibs diff
+-
+-	if export_bootdevice && export_partdevice diskdev -2; then
+-		sync
+-		if [ "$SAVE_PARTITIONS" = "1" ]; then
+-			get_partitions "/dev/$diskdev" bootdisk
+-
+-			#get block size
+-			if [ -f "/sys/block/$diskdev/queue/physical_block_size" ]; then
+-				ibs="$(cat "/sys/block/$diskdev/queue/physical_block_size")"
+-			else
+-				ibs=512
+-			fi
+-
+-			#extract the boot sector from the image
+-			get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
+-
+-			get_partitions /tmp/image.bs image
+-
+-			#compare tables
+-			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+-			if [ -n "$diff" ]; then
+-				echo "Partition layout is changed.  Full image will be written."
+-				ask_bool 0 "Abort" && exit
+-
+-				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+-				return 0
+-			fi
+-
+-			#write uboot image
+-			get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 count=1016 conv=fsync
+-			#iterate over each partition from the image and write it to the boot disk
+-			while read part start size; do
+-				part="$(($part - 2))"
+-				if export_partdevice partdev $part; then
+-					echo "Writing image to /dev/$partdev..."
+-					get_image "$@" | dd of="/dev/$partdev" ibs="$ibs" obs=1M skip="$start" count="$size" conv=fsync
+-				else
+-					echo "Unable to find partition $part device, skipped."
+-				fi
+-			done < /tmp/partmap.image
+-
+-			#copy partition uuid
+-			echo "Writing new UUID to /dev/$diskdev..."
+-			get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
++	local diskdev partdev diff
++
++	export_bootdevice && export_partdevice diskdev -2 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	sync
++
++	if [ "$SAVE_PARTITIONS" = "1" ]; then
++		get_partitions "/dev/$diskdev" bootdisk
++
++		#extract the boot sector from the image
++		get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
++
++		get_partitions /tmp/image.bs image
++
++		#compare tables
++		diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++	else
++		diff=1
++	fi
++
++	if [ -n "$diff" ]; then
++		get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++
++		# Separate removal and addtion is necessary; otherwise, partition 1
++		# will be missing if it overlaps with the old partition 2
++		partx -d - "/dev/$diskdev"
++		partx -a - "/dev/$diskdev"
++
++		return 0
++	fi
++
++	#write uboot image
++	get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 count=1016 conv=fsync
++	#iterate over each partition from the image and write it to the boot disk
++	while read part start size; do
++		part="$(($part - 2))"
++		if export_partdevice partdev $part; then
++			echo "Writing image to /dev/$partdev..."
++			get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
+ 		else
+-			get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++			echo "Unable to find partition $part device, skipped."
+ 		fi
++	done < /tmp/partmap.image
+ 
+-		sleep 1
+-	fi
++	#copy partition uuid
++	echo "Writing new UUID to /dev/$diskdev..."
++	get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
+ }

+ 25 - 0
patches/lede/0029-procd-update-to-latest-git-HEAD.patch

@@ -0,0 +1,25 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Tue, 30 May 2017 07:29:25 +0200
+Subject: procd: update to latest git HEAD
+
+e7bb2c8 upgraded: define __GNU_SOURCE
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index 775b9a64e172b250b3ba27e71fbf07aff46ede14..f9d2f4d34f866a169eb1665ac2699c54422c3c4b 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -12,9 +12,9 @@ PKG_RELEASE:=1
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git
+-PKG_SOURCE_DATE:=2017-05-29
+-PKG_SOURCE_VERSION:=992b796204caf5b0290ea4a1246b43b353b6c1d7
+-PKG_MIRROR_HASH:=effecf66ef6a7396dd26d54a5d232b4a895d9fe7aaca83063aaffc7b39a051d5
++PKG_SOURCE_DATE:=2017-05-30
++PKG_SOURCE_VERSION:=e7bb2c8d631862e1535cf6eead18387f02a69ad2
++PKG_MIRROR_HASH:=97bb96aba2db4730fd8b2edeb15f94e18caa6017d9e50a73777c14532154cade
+ CMAKE_INSTALL:=1
+ 
+ PKG_LICENSE:=GPL-2.0