aboutsummaryrefslogtreecommitdiffstats
path: root/package/system
diff options
context:
space:
mode:
authorJames <>2015-11-04 11:49:21 +0000
committerJames <>2015-11-04 11:49:21 +0000
commit716ca530e1c4515d8683c9d5be3d56b301758b66 (patch)
tree700eb5bcc1a462a5f21dcec15ce7c97ecfefa772 /package/system
downloadtrunk-47381-master.tar.gz
trunk-47381-master.tar.bz2
trunk-47381-master.zip
trunk-47381HEADmaster
Diffstat (limited to 'package/system')
-rw-r--r--package/system/ca-certificates/Makefile47
-rw-r--r--package/system/fstools/Makefile92
-rw-r--r--package/system/fstools/files/fstab.default2
-rw-r--r--package/system/fstools/files/fstab.init14
-rw-r--r--package/system/fstools/files/mount.hotplug1
-rw-r--r--package/system/fstools/files/snapshot111
-rw-r--r--package/system/mountd/Makefile48
-rw-r--r--package/system/mountd/files/mountd.config3
-rwxr-xr-xpackage/system/mountd/files/mountd.init22
-rw-r--r--package/system/mtd/Makefile54
-rw-r--r--package/system/mtd/src/Makefile21
-rw-r--r--package/system/mtd/src/crc32.c95
-rw-r--r--package/system/mtd/src/crc32.h26
-rw-r--r--package/system/mtd/src/fis.c262
-rw-r--r--package/system/mtd/src/fis.h14
-rw-r--r--package/system/mtd/src/imagetag.c407
-rw-r--r--package/system/mtd/src/jffs2.c366
-rw-r--r--package/system/mtd/src/jffs2.h216
-rw-r--r--package/system/mtd/src/linksys_bootcount.c114
-rw-r--r--package/system/mtd/src/md5.c307
-rw-r--r--package/system/mtd/src/md5.h65
-rw-r--r--package/system/mtd/src/mtd.c919
-rw-r--r--package/system/mtd/src/mtd.h31
-rw-r--r--package/system/mtd/src/seama.c179
-rw-r--r--package/system/mtd/src/seama.h108
-rw-r--r--package/system/mtd/src/trx.c223
-rw-r--r--package/system/opkg/Makefile164
-rw-r--r--package/system/opkg/files/20_migrate-feeds9
-rw-r--r--package/system/opkg/files/customfeeds.conf3
-rwxr-xr-xpackage/system/opkg/files/opkg-key56
-rw-r--r--package/system/opkg/files/opkg-smime.conf6
-rw-r--r--package/system/opkg/files/opkg.conf4
-rw-r--r--package/system/opkg/patches/001-ship-pkg-m4.patch168
-rw-r--r--package/system/opkg/patches/002-no-shave.patch37
-rw-r--r--package/system/opkg/patches/004-host_cpu.patch20
-rw-r--r--package/system/opkg/patches/007-force_static.patch71
-rw-r--r--package/system/opkg/patches/009-remove-upgrade-all.patch41
-rw-r--r--package/system/opkg/patches/011-old-config-location.patch12
-rw-r--r--package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch23
-rw-r--r--package/system/opkg/patches/014-errors-to-stderr.patch15
-rw-r--r--package/system/opkg/patches/020-avoid_getline.patch317
-rw-r--r--package/system/opkg/patches/030-fix-double-free.patch10
-rw-r--r--package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch31
-rw-r--r--package/system/opkg/patches/050-add-case-insensitive-flag.patch169
-rw-r--r--package/system/opkg/patches/060-add-find-command.patch58
-rw-r--r--package/system/opkg/patches/070-use_gzipped_pkg_list.patch120
-rw-r--r--package/system/opkg/patches/080-suppress-blank-package-fields.patch16
-rw-r--r--package/system/opkg/patches/090-suppress-blank-provides-field.patch11
-rw-r--r--package/system/opkg/patches/100-add-force-checksum.patch85
-rw-r--r--package/system/opkg/patches/110-upgrade.patch49
-rw-r--r--package/system/opkg/patches/200-usign_support.patch91
-rw-r--r--package/system/opkg/patches/210-add-force-signature.patch70
-rw-r--r--package/system/opkg/patches/220-drop-release-support.patch812
-rw-r--r--package/system/opkg/patches/230-drop_md5_support.patch161
-rw-r--r--package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch31
-rw-r--r--package/system/opkg/patches/250-add-lists-dir-switch.patch39
-rw-r--r--package/system/opkg/patches/260-add-print-package-size.patch74
-rw-r--r--package/system/procd/Makefile146
-rw-r--r--package/system/procd/files/hotplug-preinit.json20
-rw-r--r--package/system/procd/files/hotplug.json86
-rw-r--r--package/system/procd/files/nand-preinit.sh21
-rw-r--r--package/system/procd/files/nand.sh361
-rw-r--r--package/system/procd/files/procd.sh430
-rw-r--r--package/system/procd/files/reload_config15
-rw-r--r--package/system/rpcd/Makefile97
-rw-r--r--package/system/rpcd/files/rpcd.config7
-rwxr-xr-xpackage/system/rpcd/files/rpcd.init21
-rw-r--r--package/system/ubox/Makefile46
-rw-r--r--package/system/ubox/files/log.init98
-rw-r--r--package/system/ubus/Makefile80
-rw-r--r--package/system/uci/Makefile92
-rw-r--r--package/system/uci/files/lib/config/uci.sh137
-rw-r--r--package/system/udev/Config.in117
-rw-r--r--package/system/udev/Makefile157
-rw-r--r--package/system/udev/patches/0001-build-don-t-use-gc-sections.patch31
-rw-r--r--package/system/udev/patches/0002-udevd-add-lrt-for-message-queue-symbols.patch25
-rw-r--r--package/system/udev/patches/0003-add_btn_trigger_happy_define.patch13
-rw-r--r--package/system/usign/Makefile43
-rw-r--r--package/system/zram-swap/Makefile46
-rw-r--r--package/system/zram-swap/files/zram.init123
80 files changed, 8732 insertions, 0 deletions
diff --git a/package/system/ca-certificates/Makefile b/package/system/ca-certificates/Makefile
new file mode 100644
index 0000000..9c50fef
--- /dev/null
+++ b/package/system/ca-certificates/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ca-certificates
+PKG_VERSION:=20150426
+
+PKG_SOURCE:=$(PKG_NAME)_$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://ftp.debian.org/debian/pool/main/c/ca-certificates
+PKG_MD5SUM:=717455f13fb31fd014a11a468ea3895d
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ca-certificates
+ SECTION:=base
+ CATEGORY:=Base system
+ TITLE:=System CA certificates
+endef
+
+define Build/Install
+ mkdir -p \
+ $(PKG_INSTALL_DIR)/usr/sbin \
+ $(PKG_INSTALL_DIR)/usr/share/ca-certificates
+ $(call Build/Install/Default,)
+endef
+
+define Package/ca-certificates/install
+ $(INSTALL_DIR) $(1)/etc/ssl/certs
+ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/ca-certificates/*/*.crt $(1)/etc/ssl/certs/
+
+ for CERTFILE in `ls -1 $(1)/etc/ssl/certs`; do \
+ HASH=`openssl x509 -hash -noout -in $(1)/etc/ssl/certs/$$$$CERTFILE` ; \
+ SUFFIX=0 ; \
+ while [ -h "$(1)/etc/ssl/certs/$$$$HASH.$$$$SUFFIX" ]; do \
+ let "SUFFIX += 1" ; \
+ done ; \
+ $(LN) "$$$$CERTFILE" "$(1)/etc/ssl/certs/$$$$HASH.$$$$SUFFIX" ; \
+ done
+endef
+
+$(eval $(call BuildPackage,ca-certificates))
diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile
new file mode 100644
index 0000000..6a572c8
--- /dev/null
+++ b/package/system/fstools/Makefile
@@ -0,0 +1,92 @@
+#
+# Copyright (C) 2014-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=fstools
+PKG_VERSION:=2015-11-02
+
+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:=0f4571b9e484f3b3504b872afd3a11be98571c03
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+CMAKE_INSTALL:=1
+PKG_CHECK_FORMAT_SECURITY:=0
+
+PKG_LICENSE:=GPL-2.0
+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_GLIBC),-lrt)
+CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_UBIFS_EXTROOT),-DCMAKE_UBIFS_EXTROOT=y)
+
+define Package/fstools
+ SECTION:=base
+ CATEGORY:=Base system
+ DEPENDS:=+ubox +USE_GLIBC: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
+ SECTION:=base
+ CATEGORY:=Base system
+ TITLE:=Block device mounting and checking
+ DEPENDS:=+ubox +libubox +libuci
+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_DATA) $(PKG_INSTALL_DIR)/usr/lib/libfstools.so $(1)/lib/
+ $(INSTALL_BIN) ./files/snapshot $(1)/sbin/
+ $(LN) jffs2reset $(1)/sbin/jffs2mark
+endef
+
+define Package/block-mount/install
+ $(INSTALL_DIR) $(1)/sbin $(1)/lib $(1)/usr/sbin $(1)/etc/hotplug.d/block $(1)/etc/init.d/ $(1)/etc/uci-defaults/
+
+ $(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_BIN) $(PKG_INSTALL_DIR)/usr/sbin/block $(1)/sbin/
+ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libblkid-tiny.so $(1)/lib/
+ $(LN) ../../sbin/block $(1)/usr/sbin/swapon
+ $(LN) ../../sbin/block $(1)/usr/sbin/swapoff
+
+endef
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(1)/usr/include
+ $(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/
+ $(INSTALL_DIR) $(1)/usr/lib/
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libubi-utils.a $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,fstools))
+$(eval $(call BuildPackage,block-mount))
diff --git a/package/system/fstools/files/fstab.default b/package/system/fstools/files/fstab.default
new file mode 100644
index 0000000..2331e0c
--- /dev/null
+++ b/package/system/fstools/files/fstab.default
@@ -0,0 +1,2 @@
+[ ! -f /etc/config/fstab ] && ( block detect > /etc/config/fstab )
+exit 0
diff --git a/package/system/fstools/files/fstab.init b/package/system/fstools/files/fstab.init
new file mode 100644
index 0000000..f995e96
--- /dev/null
+++ b/package/system/fstools/files/fstab.init
@@ -0,0 +1,14 @@
+#!/bin/sh /etc/rc.common
+# (C) 2013 openwrt.org
+
+START=40
+
+start() {
+ echo "this file has been obsoleted. please call \"/sbin/block mount\" directly"
+ /sbin/block mount
+}
+
+stop() {
+ echo "this file has been obsoleted. please call \"/sbin/block umount\" directly"
+ /sbin/block umount
+}
diff --git a/package/system/fstools/files/mount.hotplug b/package/system/fstools/files/mount.hotplug
new file mode 100644
index 0000000..946924e
--- /dev/null
+++ b/package/system/fstools/files/mount.hotplug
@@ -0,0 +1 @@
+/sbin/block hotplug
diff --git a/package/system/fstools/files/snapshot b/package/system/fstools/files/snapshot
new file mode 100644
index 0000000..a0e0ec0
--- /dev/null
+++ b/package/system/fstools/files/snapshot
@@ -0,0 +1,111 @@
+#!/bin/sh
+# Copyright (C) 2014 OpenWrt.org
+
+
+do_snapshot_unpack() {
+ echo "- snapshot -"
+ mkdir /tmp/snapshot
+ cd /tmp/snapshot
+ snapshot_tool read
+ block=`ls block*.tar.gz 2> /dev/null`
+ [ -z "$block" ] || for a in $block; do
+ tar xzf $a -C /
+ rm -f $a
+ done
+}
+
+do_config_unpack() {
+ echo "- config -"
+ snapshot_tool config_read
+ [ -f /tmp/config.tar.gz ] && {
+ tar xzf /tmp/config.tar.gz -C /
+ rm -f /tmp/config.tar.gz
+ }
+}
+
+do_snapshot_push() {
+ cd /volatile
+ tar czf /tmp/snapshot.tar.gz *
+ snapshot_tool write
+ reboot
+}
+
+do_config_push() {
+ cd /volatile
+ tar czf /tmp/config.tar.gz *
+ snapshot_tool config_write
+}
+
+do_snapshot_upgrade() {
+ opkg update
+ [ $? -eq 0 ] || exit 1
+
+ opkg list-upgradable
+ [ $? -eq 0 ] || exit 2
+
+ UPDATES=`opkg list-upgradable | cut -d" " -f1`
+ [ -z "${UPDATES}" ] && exit 0
+
+ opkg upgrade ${UPDATES}
+ [ $? -eq 0 ] || exit 3
+
+ do_snapshot_push
+ sleep 5
+ reboot
+ sleep 10
+}
+
+do_convert_jffs2() {
+ snapshot_tool write
+ sleep 2
+ reboot -f
+}
+
+do_convert() {
+ . /lib/functions.sh
+ . /lib/upgrade/common.sh
+ ubus call system upgrade
+ touch /tmp/sysupgrade
+ cd /overlay
+ tar czf /tmp/snapshot.tar.gz *
+ kill_remaining TERM
+ sleep 3
+ kill_remaining KILL
+ run_ramfs '. /sbin/snapshot; do_convert_jffs2'
+}
+
+[ -n "$(cat /proc/mounts|grep /overlay|grep jffs2)" ] && {
+case $1 in
+convert)
+ do_convert
+ ;;
+esac
+}
+
+[ -d /volatile ] && {
+case $1 in
+push)
+ do_snapshot_push
+ ;;
+config)
+ do_config_push
+ ;;
+upgrade)
+ do_snapshot_upgrade
+ ;;
+info)
+ snapshot_tool info
+ ;;
+esac
+}
+
+[ "$SNAPSHOT" = "magic" ] && {
+case $1 in
+unpack)
+ do_snapshot_unpack
+ ;;
+config_unpack)
+ do_config_unpack
+ ;;
+esac
+}
diff --git a/package/system/mountd/Makefile b/package/system/mountd/Makefile
new file mode 100644
index 0000000..b12f8d3
--- /dev/null
+++ b/package/system/mountd/Makefile
@@ -0,0 +1,48 @@
+# Copyright (C) 2009-2012 OpenWrt.org
+# All rights reserved.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mountd
+PKG_VERSION:=2015-08-19
+
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=http://git.openwrt.org/project/mountd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=d5926d3848b1e9c6147f0bd908a35d20cdef50b5
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+CMAKE_INSTALL:=1
+
+PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
+PKG_CHECK_FORMAT_SECURITY:=0
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/mountd
+ SECTION:=utils
+ CATEGORY:=Utilities
+ TITLE:=OpenWrt automount daemon
+ DEPENDS:=@USB_SUPPORT +uci +kmod-usb-storage +kmod-fs-autofs4
+ URL:=http://www.openwrt.org
+endef
+
+define Package/mountd/description
+ openwrt automount daemon
+endef
+
+define Package/mountd/conffiles
+/etc/config/mountd
+endef
+
+define Package/mountd/install
+ $(INSTALL_DIR) $(1)/sbin/ $(1)/etc/config/ $(1)/etc/init.d/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/mountd $(1)/sbin/
+ $(INSTALL_DATA) ./files/mountd.config $(1)/etc/config/mountd
+ $(INSTALL_BIN) ./files/mountd.init $(1)/etc/init.d/mountd
+endef
+
+$(eval $(call BuildPackage,mountd))
diff --git a/package/system/mountd/files/mountd.config b/package/system/mountd/files/mountd.config
new file mode 100644
index 0000000..5610129
--- /dev/null
+++ b/package/system/mountd/files/mountd.config
@@ -0,0 +1,3 @@
+config mountd mountd
+ option timeout 60
+ option path /tmp/mounts/
diff --git a/package/system/mountd/files/mountd.init b/package/system/mountd/files/mountd.init
new file mode 100755
index 0000000..772bd6e
--- /dev/null
+++ b/package/system/mountd/files/mountd.init
@@ -0,0 +1,22 @@
+#!/bin/sh /etc/rc.common
+
+START=80
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+SERVICE_PID_FILE=/var/run/mountd.pid
+
+MOUNTD_BIN=/sbin/mountd
+
+start()
+{
+ P="$(uci get mountd.mountd.path)"
+ [ -n "$P" -a ! -f "$P" ] && mkdir -p $P
+
+ service_start $MOUNTD_BIN -f
+}
+
+stop()
+{
+ service_stop $MOUNTD_BIN
+}
diff --git a/package/system/mtd/Makefile b/package/system/mtd/Makefile
new file mode 100644
index 0000000..ae1922f
--- /dev/null
+++ b/package/system/mtd/Makefile
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=mtd
+PKG_RELEASE:=21
+
+PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
+STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
+
+PKG_LICENSE:=GPL-2.0+
+PKG_LICENSE_FILES:=
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/mtd
+ SECTION:=utils
+ CATEGORY:=Base system
+ DEPENDS:=+libubox
+ TITLE:=Update utility for trx firmware images
+endef
+
+define Package/mtd/description
+ This package contains an utility useful to upgrade from other firmware or
+ older OpenWrt releases.
+endef
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+target=$(firstword $(subst -, ,$(BOARD)))
+
+MAKE_FLAGS += TARGET="$(target)"
+TARGET_CFLAGS := $(TARGET_CFLAGS) -Dtarget_$(target)=1 -Wall
+
+ifdef CONFIG_MTD_REDBOOT_PARTS
+ MAKE_FLAGS += FIS_SUPPORT=1
+ TARGET_CFLAGS += -DFIS_SUPPORT=1
+endif
+
+define Package/mtd/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/mtd $(1)/sbin/
+endef
+
+$(eval $(call BuildPackage,mtd))
diff --git a/package/system/mtd/src/Makefile b/package/system/mtd/src/Makefile
new file mode 100644
index 0000000..40a165e
--- /dev/null
+++ b/package/system/mtd/src/Makefile
@@ -0,0 +1,21 @@
+CC = gcc
+CFLAGS += -Wall
+LDFLAGS += -lubox
+
+obj = mtd.o jffs2.o crc32.o md5.o
+obj.seama = seama.o md5.o
+obj.ar71xx = trx.o $(obj.seama)
+obj.brcm = trx.o
+obj.brcm47xx = $(obj.brcm)
+obj.bcm53xx = $(obj.brcm)
+obj.brcm63xx = imagetag.o
+obj.ramips = $(obj.seama)
+obj.mvebu = linksys_bootcount.o
+
+ifdef FIS_SUPPORT
+ obj += fis.o
+endif
+
+mtd: $(obj) $(obj.$(TARGET))
+clean:
+ rm -f *.o jffs2
diff --git a/package/system/mtd/src/crc32.c b/package/system/mtd/src/crc32.c
new file mode 100644
index 0000000..6b1e50c
--- /dev/null
+++ b/package/system/mtd/src/crc32.c
@@ -0,0 +1,95 @@
+/*
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ */
+
+#include <stdint.h>
+
+const uint32_t crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/package/system/mtd/src/crc32.h b/package/system/mtd/src/crc32.h
new file mode 100644
index 0000000..68f8ee4
--- /dev/null
+++ b/package/system/mtd/src/crc32.h
@@ -0,0 +1,26 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <stdint.h>
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+ const unsigned char *s = ss;
+ while (--len >= 0)
+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+ return val;
+}
+
+static inline unsigned int crc32buf(char *buf, size_t len)
+{
+ return crc32(0xFFFFFFFF, buf, len);
+}
+
+
+
+#endif
diff --git a/package/system/mtd/src/fis.c b/package/system/mtd/src/fis.c
new file mode 100644
index 0000000..f825f59
--- /dev/null
+++ b/package/system/mtd/src/fis.c
@@ -0,0 +1,262 @@
+/*
+ * FIS table updating code for mtd
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * 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/mman.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "crc32.h"
+#include "mtd.h"
+#include "fis.h"
+
+struct fis_image_hdr {
+ unsigned char name[16];
+ uint32_t flash_base;
+ uint32_t mem_base;
+ uint32_t size;
+ uint32_t entry_point;
+ uint32_t data_length;
+} __attribute__((packed));
+
+struct fis_image_crc {
+ uint32_t desc;
+ uint32_t file;
+} __attribute__((packed));
+
+struct fis_image_desc {
+ struct fis_image_hdr hdr;
+ char _pad[256 - sizeof(struct fis_image_hdr) - sizeof(struct fis_image_crc)];
+ struct fis_image_crc crc;
+} __attribute__((packed));
+
+static int fis_fd = -1;
+static struct fis_image_desc *fis_desc;
+static int fis_erasesize = 0;
+
+static void
+fis_close(void)
+{
+ if (fis_desc)
+ munmap(fis_desc, fis_erasesize);
+
+ if (fis_fd >= 0)
+ close(fis_fd);
+
+ fis_fd = -1;
+ fis_desc = NULL;
+}
+
+static struct fis_image_desc *
+fis_open(void)
+{
+ struct fis_image_desc *desc;
+
+ if (fis_fd >= 0)
+ fis_close();
+
+ fis_fd = mtd_check_open("FIS directory");
+ if (fis_fd < 0)
+ goto error;
+
+ close(fis_fd);
+ fis_fd = mtd_open("FIS directory", true);
+ if (fis_fd < 0)
+ goto error;
+
+ fis_erasesize = erasesize;
+ desc = mmap(NULL, erasesize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fis_fd, 0);
+ if (desc == MAP_FAILED)
+ goto error;
+
+ fis_desc = desc;
+ return desc;
+
+error:
+ fis_close();
+ return NULL;
+}
+
+int
+fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
+{
+ struct fis_image_desc *desc;
+ void *end;
+ int found = 0;
+ int i;
+
+ desc = fis_open();
+ if (!desc)
+ return -1;
+
+ for (i = 0; i < n_new - 1; i++) {
+ if (!new[i].size) {
+ fprintf(stderr, "FIS error: only the last partition can detect the size automatically\n");
+ i = -1;
+ goto done;
+ }
+ }
+
+ end = desc;
+ end = (char *) end + fis_erasesize;
+ while ((void *) desc < end) {
+ if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
+ break;
+
+ for (i = 0; i < n_old; i++) {
+ if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) {
+ found++;
+ goto next;
+ }
+ }
+next:
+ desc++;
+ continue;
+ }
+
+ if (found == n_old)
+ i = 1;
+ else
+ i = -1;
+
+done:
+ fis_close();
+ return i;
+}
+
+int
+fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
+{
+ struct fis_image_desc *fisdir = NULL;
+ struct fis_image_desc *redboot = NULL;
+ struct fis_image_desc *first = NULL;
+ struct fis_image_desc *last = NULL;
+ struct fis_image_desc *first_fb = NULL;
+ struct fis_image_desc *last_fb = NULL;
+ struct fis_image_desc *desc;
+ struct fis_part *part;
+ uint32_t offset = 0, size = 0;
+ char *start, *end, *tmp;
+ int i;
+
+ desc = fis_open();
+ if (!desc)
+ return -1;
+
+ if (!quiet)
+ fprintf(stderr, "Updating FIS table... \n");
+
+ start = (char *) desc;
+ end = (char *) desc + fis_erasesize;
+ while ((char *) desc < end) {
+ if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
+ break;
+
+ if (!strcmp((char *) desc->hdr.name, "FIS directory"))
+ fisdir = desc;
+
+ if (!strcmp((char *) desc->hdr.name, "RedBoot"))
+ redboot = desc;
+
+ /* update max offset */
+ if (offset < desc->hdr.flash_base)
+ offset = desc->hdr.flash_base;
+
+ for (i = 0; i < n_old; i++) {
+ if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) {
+ last = desc;
+ if (!first)
+ first = desc;
+ break;
+ }
+ }
+ desc++;
+ }
+ desc--;
+
+ first_fb = first;
+ last_fb = last;
+
+ if (first_fb->hdr.flash_base > last_fb->hdr.flash_base) {
+ first_fb = last;
+ last_fb = first;
+ }
+
+ /* determine size of available space */
+ desc = (struct fis_image_desc *) start;
+ while ((char *) desc < end) {
+ if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
+ break;
+
+ if (desc->hdr.flash_base > last_fb->hdr.flash_base &&
+ desc->hdr.flash_base < offset)
+ offset = desc->hdr.flash_base;
+
+ desc++;
+ }
+ desc--;
+
+ size = offset - first_fb->hdr.flash_base;
+
+#ifdef notyet
+ desc = first - 1;
+ if (redboot && (desc >= redboot)) {
+ if (first->hdr.flash_base - desc->hdr.size > desc->hdr.flash_base) {
+ int delta = first->hdr.flash_base - desc->hdr.size - desc->hdr.flash_base;
+
+ offset -= delta;
+ size += delta;
+ }
+ }
+#endif
+
+ last++;
+ desc = first + n_new;
+ offset = first_fb->hdr.flash_base;
+
+ if (desc != last) {
+ if (desc > last)
+ tmp = (char *) desc;
+ else
+ tmp = (char *) last;
+
+ memmove(desc, last, end - tmp);
+ if (desc < last) {
+ tmp = end - (last - desc) * sizeof(struct fis_image_desc);
+ memset(tmp, 0xff, tmp - end);
+ }
+ }
+
+ for (part = new, desc = first; desc < first + n_new; desc++, part++) {
+ memset(desc, 0, sizeof(struct fis_image_desc));
+ memcpy(desc->hdr.name, part->name, sizeof(desc->hdr.name));
+ desc->crc.desc = 0;
+ desc->crc.file = 0;
+
+ desc->hdr.flash_base = offset;
+ desc->hdr.mem_base = part->loadaddr;
+ desc->hdr.entry_point = part->loadaddr;
+ desc->hdr.size = (part->size > 0) ? part->size : size;
+ desc->hdr.data_length = desc->hdr.size;
+
+ offset += desc->hdr.size;
+ size -= desc->hdr.size;
+ }
+
+ msync(fis_desc, fis_erasesize, MS_SYNC|MS_INVALIDATE);
+ fis_close();
+
+ return 0;
+}
diff --git a/package/system/mtd/src/fis.h b/package/system/mtd/src/fis.h
new file mode 100644
index 0000000..bdf1103
--- /dev/null
+++ b/package/system/mtd/src/fis.h
@@ -0,0 +1,14 @@
+#ifndef __FIS_H
+#define __FIS_H
+
+struct fis_part {
+ unsigned char name[16];
+ uint32_t offset;
+ uint32_t loadaddr;
+ uint32_t size;
+};
+
+int fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new);
+int fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new);
+
+#endif
diff --git a/package/system/mtd/src/imagetag.c b/package/system/mtd/src/imagetag.c
new file mode 100644
index 0000000..b850837
--- /dev/null
+++ b/package/system/mtd/src/imagetag.c
@@ -0,0 +1,407 @@
+/*
+ * imagetag.c
+ *
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ * Copyrigth (C) 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include "mtd.h"
+#include "crc32.h"
+
+#define TAGVER_LEN 4 /* Length of Tag Version */
+#define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */
+#define SIG1_LEN 20 /* Company Signature 1 Length */
+#define SIG2_LEN 14 /* Company Signature 2 Length */
+#define BOARDID_LEN 16 /* Length of BoardId */
+#define ENDIANFLAG_LEN 2 /* Endian Flag Length */
+#define CHIPID_LEN 6 /* Chip Id Length */
+#define IMAGE_LEN 10 /* Length of Length Field */
+#define ADDRESS_LEN 12 /* Length of Address field */
+#define DUALFLAG_LEN 2 /* Dual Image flag Length */
+#define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */
+#define RSASIG_LEN 20 /* Length of RSA Signature in tag */
+#define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */
+#define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */
+
+#define NUM_PIRELLI 2
+#define IMAGETAG_CRC_START 0xFFFFFFFF
+
+#define PIRELLI_BOARDS { \
+ "AGPF-S0", \
+ "DWV-S0", \
+}
+/*
+ * The broadcom firmware assumes the rootfs starts the image,
+ * therefore uses the rootfs start (flash_image_address)
+ * to determine where to flash the image. Since we have the kernel first
+ * we have to give it the kernel address, but the crc uses the length
+ * associated with this address (root_length), which is added to the kernel
+ * length (kernel_length) to determine the length of image to flash and thus
+ * needs to be rootfs + deadcode (jffs2 EOF marker)
+*/
+
+struct bcm_tag {
+ /* 0-3: Version of the image tag */
+ char tag_version[TAGVER_LEN];
+ /* 4-23: Company Line 1 */
+ char sig_1[SIG1_LEN];
+ /* 24-37: Company Line 2 */
+ char sig_2[SIG2_LEN];
+ /* 38-43: Chip this image is for */
+ char chip_id[CHIPID_LEN];
+ /* 44-59: Board name */
+ char board_id[BOARDID_LEN];
+ /* 60-61: Map endianness -- 1 BE 0 LE */
+ char big_endian[ENDIANFLAG_LEN];
+ /* 62-71: Total length of image */
+ char total_length[IMAGE_LEN];
+ /* 72-83: Address in memory of CFE */
+ char cfe__address[ADDRESS_LEN];
+ /* 84-93: Size of CFE */
+ char cfe_length[IMAGE_LEN];
+ /* 94-105: Address in memory of image start
+ * (kernel for OpenWRT, rootfs for stock firmware)
+ */
+ char flash_image_start[ADDRESS_LEN];
+ /* 106-115: Size of rootfs */
+ char root_length[IMAGE_LEN];
+ /* 116-127: Address in memory of kernel */
+ char kernel_address[ADDRESS_LEN];
+ /* 128-137: Size of kernel */
+ char kernel_length[IMAGE_LEN];
+ /* 138-139: Unused at the moment */
+ char dual_image[DUALFLAG_LEN];
+ /* 140-141: Unused at the moment */
+ char inactive_flag[INACTIVEFLAG_LEN];
+ /* 142-161: RSA Signature (not used; some vendors may use this) */
+ char rsa_signature[RSASIG_LEN];
+ /* 162-191: Compilation and related information (not used in OpenWrt) */
+ char information1[TAGINFO1_LEN];
+ /* 192-195: Version flash layout */
+ char flash_layout_ver[FLASHLAYOUTVER_LEN];
+ /* 196-199: kernel+rootfs CRC32 */
+ __u32 fskernel_crc;
+ /* 200-215: Unused except on Alice Gate where is is information */
+ char information2[TAGINFO2_LEN];
+ /* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */
+ __u32 image_crc;
+ /* 220-223: CRC32 of rootfs partition */
+ __u32 rootfs_crc;
+ /* 224-227: CRC32 of kernel partition */
+ __u32 kernel_crc;
+ /* 228-231: Image sequence number */
+ char image_sequence[4];
+ /* 222-235: Openwrt: real rootfs length */
+ __u32 real_rootfs_length;
+ /* 236-239: CRC32 of header excluding last 20 bytes */
+ __u32 header_crc;
+ /* 240-255: Unused at present */
+ char reserved2[16];
+};
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+#define CRC_START 0xFFFFFFFF
+
+static uint32_t strntoul(char *str, char **endptr, int base, size_t len) {
+ char *newstr;
+ uint32_t res = 0;
+
+ newstr = calloc(len + 1, sizeof(char));
+ if (newstr) {
+ strncpy(newstr, str, len);
+ res = strtoul(newstr, endptr, base);
+ free(newstr);
+ }
+ return res;
+}
+
+uint32_t compute_crc32(uint32_t crc, off_t start, size_t compute_len, int fd)
+{
+ uint8_t readbuf[1024];
+ ssize_t res;
+ off_t offset = start;
+
+ /* Read a buffer's worth of bytes */
+ while (fd && (compute_len >= sizeof(readbuf))) {
+ res = pread(fd, readbuf, sizeof(readbuf), offset);
+ crc = crc32(crc, readbuf, res);
+ compute_len = compute_len - res;
+ offset += res;
+ }
+
+ /* Less than buffer-size bytes remains, read compute_len bytes */
+ if (fd && (compute_len > 0)) {
+ res = pread(fd, readbuf, compute_len, offset);
+ crc = crc32(crc, readbuf, res);
+ }
+
+ return crc;
+}
+
+int
+trx_fixup(int fd, const char *name)
+{
+ struct mtd_info_user mtdInfo;
+ unsigned long len;
+ void *ptr, *scan;
+ int bfd;
+ struct bcm_tag *tag;
+ ssize_t res;
+ uint32_t cfelen, imagelen, imagestart, rootfslen;
+ uint32_t imagecrc, rootfscrc, headercrc;
+ uint32_t offset = 0;
+ cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
+
+
+ if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
+ fprintf(stderr, "Failed to get mtd info\n");
+ goto err;
+ }
+
+ len = mtdInfo.size;
+ if (mtdInfo.size <= 0) {
+ fprintf(stderr, "Invalid MTD device size\n");
+ goto err;
+ }
+
+ bfd = mtd_open(name, true);
+ ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
+ if (!ptr || (ptr == (void *) -1)) {
+ perror("mmap");
+ goto err1;
+ }
+
+ tag = (struct bcm_tag *) (ptr);
+
+ cfelen = strntoul(&tag->cfe_length[0], NULL, 10, IMAGE_LEN);
+ if (cfelen) {
+ fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n");
+ exit(1);
+ }
+
+ headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd);
+ if (headercrc != *(uint32_t *)(&tag->header_crc)) {
+ fprintf(stderr, "Tag verify failed. This may not be a valid image.\n");
+ exit(1);
+ }
+
+ sprintf(&tag->root_length[0], "%u", 0);
+ strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN);
+
+ imagestart = sizeof(tag);
+ memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t));
+ memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t));
+ rootfscrc = CRC_START;
+ memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t));
+ headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc));
+ memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t));
+
+ msync(ptr, sizeof(struct bcm_tag), MS_SYNC|MS_INVALIDATE);
+ munmap(ptr, len);
+ close(bfd);
+ return 0;
+
+err1:
+ close(bfd);
+err:
+ fprintf(stderr, "Error fixing up imagetag header\n");
+ return -1;
+}
+
+
+int
+trx_check(int imagefd, const char *mtd, char *buf, int *len)
+{
+ struct bcm_tag *tag = (const struct bcm_tag *) buf;
+ int fd;
+ uint32_t headerCRC;
+ uint32_t imageLen;
+
+ if (strcmp(mtd, "linux") != 0)
+ return 1;
+
+ *len = read(imagefd, buf, sizeof(struct bcm_tag));
+ if (*len < sizeof(struct bcm_tag)) {
+ fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
+ return 0;
+ }
+ headerCRC = crc32buf(buf, offsetof(struct bcm_tag, header_crc));
+ if (*(uint32_t *)(&tag->header_crc) != headerCRC) {
+
+ if (quiet < 2) {
+ fprintf(stderr, "Bad header CRC got %08x, calculated %08x\n",
+ *(uint32_t *)(&tag->header_crc), headerCRC);
+ fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
+ "Please specify the correct file or use -f to force.\n");
+ }
+ return 0;
+ }
+
+ /* check if image fits to mtd device */
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ imageLen = strntoul(&tag->total_length[0], NULL, 10, IMAGE_LEN);
+
+ if(mtdsize < imageLen) {
+ fprintf(stderr, "Image too big for partition: %s\n", mtd);
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+ return 1;
+}
+
+int
+mtd_fixtrx(const char *mtd, size_t offset)
+{
+ int fd;
+ struct bcm_tag *tag;
+ char *buf;
+ ssize_t res;
+ size_t block_offset;
+ uint32_t cfelen, imagelen, imagestart, rootfslen;
+ uint32_t imagecrc, rootfscrc, headercrc;
+ cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
+
+ if (quiet < 2)
+ fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
+
+ block_offset = offset & ~(erasesize - 1);
+ offset -= block_offset;
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ if (block_offset + erasesize > mtdsize) {
+ fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
+ exit(1);
+ }
+
+ buf = malloc(erasesize);
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ res = pread(fd, buf, erasesize, block_offset);
+ if (res != erasesize) {
+ perror("pread");
+ exit(1);
+ }
+
+ tag = (struct bcm_tag *) (buf + offset);
+
+ cfelen = strntoul(tag->cfe_length, NULL, 10, IMAGE_LEN);
+ if (cfelen) {
+ fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n");
+ exit(1);
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "Verifying we actually have an imagetag.\n");
+ }
+
+ headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd);
+ if (headercrc != *(uint32_t *)(&tag->header_crc)) {
+ fprintf(stderr, "Tag verify failed. This may not be a valid image.\n");
+ exit(1);
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "Checking current fixed status.\n");
+ }
+
+ rootfslen = strntoul(&tag->root_length[0], NULL, 10, IMAGE_LEN);
+ if (rootfslen == 0) {
+ if (quiet < 2)
+ fprintf(stderr, "Header already fixed, exiting\n");
+ close(fd);
+ return 0;
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "Setting root length to 0.\n");
+ }
+
+ sprintf(&tag->root_length[0], "%u", 0);
+ strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN);
+
+ if (quiet < 2) {
+ fprintf(stderr, "Recalculating CRCs.\n");
+ }
+
+ imagestart = sizeof(tag);
+ memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t));
+ memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t));
+ rootfscrc = CRC_START;
+ memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t));
+ headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc));
+ memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t));
+
+ if (quiet < 2) {
+ fprintf(stderr, "Erasing imagetag block\n");
+ }
+
+ if (mtd_erase_block(fd, block_offset)) {
+ fprintf(stderr, "Can't erase block at 0x%x (%s)\n", block_offset, strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "New image crc32: 0x%x, rewriting block\n",
+ *(uint32_t *)(&tag->image_crc));
+ fprintf(stderr, "New header crc32: 0x%x, rewriting block\n", headercrc);
+ }
+
+ if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+ fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Done.\n");
+
+ close (fd);
+ sync();
+ return 0;
+
+}
diff --git a/package/system/mtd/src/jffs2.c b/package/system/mtd/src/jffs2.c
new file mode 100644
index 0000000..c29fb33
--- /dev/null
+++ b/package/system/mtd/src/jffs2.c
@@ -0,0 +1,366 @@
+/*
+ * jffs2 on-disk structure generator for mtd
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * 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.
+ * Based on:
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ * Copyright © 2001-2007 Red Hat, Inc.
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <endian.h>
+#include "jffs2.h"
+#include "crc32.h"
+#include "mtd.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define CLEANMARKER "\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98"
+#else
+# define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4"
+#endif
+
+static int last_ino = 0;
+static int last_version = 0;
+static char *buf = NULL;
+static int ofs = 0;
+static int outfd = -1;
+static int mtdofs = 0;
+static int target_ino = 0;
+
+static void prep_eraseblock(void);
+
+static void pad(int size)
+{
+ if ((ofs % size == 0) && (ofs < erasesize))
+ return;
+
+ if (ofs < erasesize) {
+ memset(buf + ofs, 0xff, (size - (ofs % size)));
+ ofs += (size - (ofs % size));
+ }
+ ofs = ofs % erasesize;
+ if (ofs == 0) {
+ while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize)) {
+ if (!quiet)
+ fprintf(stderr, "\nSkipping bad block at 0x%08x ", mtdofs);
+
+ mtdofs += erasesize;
+
+ /* Move the file pointer along over the bad block. */
+ lseek(outfd, erasesize, SEEK_CUR);
+ }
+ mtd_erase_block(outfd, mtdofs);
+ write(outfd, buf, erasesize);
+ mtdofs += erasesize;
+ }
+}
+
+static inline int rbytes(void)
+{
+ return erasesize - (ofs % erasesize);
+}
+
+static inline void add_data(char *ptr, int len)
+{
+ if (ofs + len > erasesize) {
+ pad(erasesize);
+ prep_eraseblock();
+ }
+ memcpy(buf + ofs, ptr, len);
+ ofs += len;
+}
+
+static void prep_eraseblock(void)
+{
+ if (ofs > 0)
+ return;
+
+ add_data(CLEANMARKER, sizeof(CLEANMARKER) - 1);
+}
+
+static int add_dirent(const char *name, const char type, int parent)
+{
+ struct jffs2_raw_dirent *de;
+
+ if (ofs - erasesize < sizeof(struct jffs2_raw_dirent) + strlen(name))
+ pad(erasesize);
+
+ prep_eraseblock();
+ last_ino++;
+ memset(buf + ofs, 0, sizeof(struct jffs2_raw_dirent));
+ de = (struct jffs2_raw_dirent *) (buf + ofs);
+
+ de->magic = JFFS2_MAGIC_BITMASK;
+ de->nodetype = JFFS2_NODETYPE_DIRENT;
+ de->type = type;
+ de->name_crc = crc32(0, name, strlen(name));
+ de->ino = last_ino++;
+ de->pino = parent;
+ de->totlen = sizeof(*de) + strlen(name);
+ de->hdr_crc = crc32(0, (void *) de, sizeof(struct jffs2_unknown_node) - 4);
+ de->version = last_version++;
+ de->mctime = 0;
+ de->nsize = strlen(name);
+ de->node_crc = crc32(0, (void *) de, sizeof(*de) - 8);
+ memcpy(de->name, name, strlen(name));
+
+ ofs += sizeof(struct jffs2_raw_dirent) + de->nsize;
+ pad(4);
+
+ return de->ino;
+}
+
+static int add_dir(const char *name, int parent)
+{
+ struct jffs2_raw_inode ri;
+ int inode;
+
+ inode = add_dirent(name, IFTODT(S_IFDIR), parent);
+
+ if (rbytes() < sizeof(ri))
+ pad(erasesize);
+ prep_eraseblock();
+
+ memset(&ri, 0, sizeof(ri));
+ ri.magic = JFFS2_MAGIC_BITMASK;
+ ri.nodetype = JFFS2_NODETYPE_INODE;
+ ri.totlen = sizeof(ri);
+ ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
+
+ ri.ino = inode;
+ ri.mode = S_IFDIR | 0755;
+ ri.uid = ri.gid = 0;
+ ri.atime = ri.ctime = ri.mtime = 0;
+ ri.isize = ri.csize = ri.dsize = 0;
+ ri.version = 1;
+ ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
+ ri.data_crc = 0;
+
+ add_data((char *) &ri, sizeof(ri));
+ pad(4);
+ return inode;
+}
+
+static void add_file(const char *name, int parent)
+{
+ int inode, f_offset = 0, fd;
+ struct jffs2_raw_inode ri;
+ struct stat st;
+ char wbuf[4096];
+ const char *fname;
+
+ if (stat(name, &st)) {
+ fprintf(stderr, "File %s does not exist\n", name);
+ return;
+ }
+
+ fname = strrchr(name, '/');
+ if (fname)
+ fname++;
+ else
+ fname = name;
+
+ inode = add_dirent(fname, IFTODT(S_IFREG), parent);
+ memset(&ri, 0, sizeof(ri));
+ ri.magic = JFFS2_MAGIC_BITMASK;
+ ri.nodetype = JFFS2_NODETYPE_INODE;
+
+ ri.ino = inode;
+ ri.mode = st.st_mode;
+ ri.uid = ri.gid = 0;
+ ri.atime = st.st_atime;
+ ri.ctime = st.st_ctime;
+ ri.mtime = st.st_mtime;
+ ri.isize = st.st_size;
+ ri.compr = 0;
+ ri.usercompr = 0;
+
+ fd = open(name, 0);
+ if (fd < 0) {
+ fprintf(stderr, "File %s does not exist\n", name);
+ return;
+ }
+
+ for (;;) {
+ int len = 0;
+
+ for (;;) {
+ len = rbytes() - sizeof(ri);
+ if (len > 128)
+ break;
+
+ pad(erasesize);
+ prep_eraseblock();
+ }
+
+ if (len > sizeof(wbuf))
+ len = sizeof(wbuf);
+
+ len = read(fd, wbuf, len);
+ if (len <= 0)
+ break;
+
+ ri.totlen = sizeof(ri) + len;
+ ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
+ ri.version = ++last_version;
+ ri.offset = f_offset;
+ ri.csize = ri.dsize = len;
+ ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
+ ri.data_crc = crc32(0, wbuf, len);
+ f_offset += len;
+ add_data((char *) &ri, sizeof(ri));
+ add_data(wbuf, len);
+ pad(4);
+ prep_eraseblock();
+ }
+
+ close(fd);
+}
+
+int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
+{
+ outfd = fd;
+ mtdofs = ofs;
+
+ buf = malloc(erasesize);
+ target_ino = 1;
+ if (!last_ino)
+ last_ino = 1;
+ add_file(filename, target_ino);
+ pad(erasesize);
+
+ /* add eof marker, pad to eraseblock size and write the data */
+ add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
+ pad(erasesize);
+ free(buf);
+
+ return (mtdofs - ofs);
+}
+
+void mtd_parse_jffs2data(const char *buf, const char *dir)
+{
+ struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
+ unsigned int ofs = 0;
+
+ while (ofs < erasesize) {
+ node = (struct jffs2_unknown_node *) (buf + ofs);
+ if (node->magic != 0x1985)
+ break;
+
+ ofs += PAD(node->totlen);
+ if (node->nodetype == JFFS2_NODETYPE_DIRENT) {
+ struct jffs2_raw_dirent *de = (struct jffs2_raw_dirent *) node;
+
+ /* is this the right directory name and is it a subdirectory of / */
+ if (*dir && (de->pino == 1) && !strncmp((char *) de->name, dir, de->nsize))
+ target_ino = de->ino;
+
+ /* store the last inode and version numbers for adding extra files */
+ if (last_ino < de->ino)
+ last_ino = de->ino;
+ if (last_version < de->version)
+ last_version = de->version;
+ }
+ }
+}
+
+int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
+{
+ int err = -1, fdeof = 0;
+
+ outfd = mtd_check_open(mtd);
+ if (outfd < 0)
+ return -1;
+
+ if (quiet < 2)
+ fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd);
+
+ buf = malloc(erasesize);
+ if (!buf) {
+ fprintf(stderr, "Out of memory!\n");
+ goto done;
+ }
+
+ if (!*dir)
+ target_ino = 1;
+
+ /* parse the structure of the jffs2 first
+ * locate the directory that the file is going to be placed in */
+ for(;;) {
+ struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
+
+ if (read(outfd, buf, erasesize) != erasesize) {
+ fdeof = 1;
+ break;
+ }
+ mtdofs += erasesize;
+
+ if (node->magic == 0x8519) {
+ fprintf(stderr, "Error: wrong endianness filesystem\n");
+ goto done;
+ }
+
+ /* assume no magic == end of filesystem
+ * the filesystem will probably end with be32(0xdeadc0de) */
+ if (node->magic != 0x1985)
+ break;
+
+ mtd_parse_jffs2data(buf, dir);
+ }
+
+ if (fdeof) {
+ fprintf(stderr, "Error: No room for additional data\n");
+ goto done;
+ }
+
+ /* jump back one eraseblock */
+ mtdofs -= erasesize;
+ lseek(outfd, mtdofs, SEEK_SET);
+
+ ofs = 0;
+
+ if (!last_ino)
+ last_ino = 1;
+
+ if (!target_ino)
+ target_ino = add_dir(dir, 1);
+
+ add_file(filename, target_ino);
+ pad(erasesize);
+
+ /* add eof marker, pad to eraseblock size and write the data */
+ add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
+ pad(erasesize);
+
+ err = 0;
+
+ if (trx_fixup) {
+ trx_fixup(outfd, mtd);
+ }
+
+done:
+ close(outfd);
+ if (buf)
+ free(buf);
+
+ return err;
+}
diff --git a/package/system/mtd/src/jffs2.h b/package/system/mtd/src/jffs2.h
new file mode 100644
index 0000000..858e77a
--- /dev/null
+++ b/package/system/mtd/src/jffs2.h
@@ -0,0 +1,216 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ *
+ *
+ */
+
+#ifndef __LINUX_JFFS2_H__
+#define __LINUX_JFFS2_H__
+
+#define JFFS2_SUPER_MAGIC 0x72b6
+
+/* You must include something which defines the C99 uintXX_t types.
+ We don't do it from here because this file is used in too many
+ different environments. */
+
+/* Values we may expect to find in the 'magic' field */
+#define JFFS2_OLD_MAGIC_BITMASK 0x1984
+#define JFFS2_MAGIC_BITMASK 0x1985
+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
+#define JFFS2_EMPTY_BITMASK 0xffff
+#define JFFS2_DIRTY_BITMASK 0x0000
+
+/* Summary node MAGIC marker */
+#define JFFS2_SUM_MAGIC 0x02851885
+
+/* We only allow a single char for length, and 0xFF is empty flash so
+ we don't want it confused with a real length. Hence max 254.
+*/
+#define JFFS2_MAX_NAME_LEN 254
+
+/* How small can we sensibly write nodes? */
+#define JFFS2_MIN_DATA_LEN 128
+
+#define JFFS2_COMPR_NONE 0x00
+#define JFFS2_COMPR_ZERO 0x01
+#define JFFS2_COMPR_RTIME 0x02
+#define JFFS2_COMPR_RUBINMIPS 0x03
+#define JFFS2_COMPR_COPY 0x04
+#define JFFS2_COMPR_DYNRUBIN 0x05
+#define JFFS2_COMPR_ZLIB 0x06
+/* Compatibility flags. */
+#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
+#define JFFS2_NODE_ACCURATE 0x2000
+/* INCOMPAT: Fail to mount the filesystem */
+#define JFFS2_FEATURE_INCOMPAT 0xc000
+/* ROCOMPAT: Mount read-only */
+#define JFFS2_FEATURE_ROCOMPAT 0x8000
+/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
+/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
+
+#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
+#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
+#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
+
+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
+
+/* XATTR Related */
+#define JFFS2_XPREFIX_USER 1 /* for "user." */
+#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */
+#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */
+#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */
+#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */
+
+#define JFFS2_ACL_VERSION 0x0001
+
+// Maybe later...
+//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
+
+
+#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
+ mount time, don't wait for it to
+ happen later */
+#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
+ compression type */
+
+
+/* These can go once we've made sure we've caught all uses without
+ byteswapping */
+
+typedef uint32_t jint32_t;
+
+typedef uint32_t jmode_t;
+
+typedef uint16_t jint16_t;
+
+struct jffs2_unknown_node
+{
+ /* All start like this */
+ jint16_t magic;
+ jint16_t nodetype;
+ jint32_t totlen; /* So we can skip over nodes we don't grok */
+ jint32_t hdr_crc;
+};
+
+struct jffs2_raw_dirent
+{
+ jint16_t magic;
+ jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t pino;
+ jint32_t version;
+ jint32_t ino; /* == zero for unlink */
+ jint32_t mctime;
+ uint8_t nsize;
+ uint8_t type;
+ uint8_t unused[2];
+ jint32_t node_crc;
+ jint32_t name_crc;
+ uint8_t name[0];
+};
+
+/* The JFFS2 raw inode structure: Used for storage on physical media. */
+/* The uid, gid, atime, mtime and ctime members could be longer, but
+ are left like this for space efficiency. If and when people decide
+ they really need them extended, it's simple enough to add support for
+ a new type of raw node.
+*/
+struct jffs2_raw_inode
+{
+ jint16_t magic; /* A constant magic number. */
+ jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */
+ jint32_t totlen; /* Total length of this node (inc data, etc.) */
+ jint32_t hdr_crc;
+ jint32_t ino; /* Inode number. */
+ jint32_t version; /* Version number. */
+ jmode_t mode; /* The file's type or mode. */
+ jint16_t uid; /* The file's owner. */
+ jint16_t gid; /* The file's group. */
+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */
+ jint32_t atime; /* Last access time. */
+ jint32_t mtime; /* Last modification time. */
+ jint32_t ctime; /* Change time. */
+ jint32_t offset; /* Where to begin to write. */
+ jint32_t csize; /* (Compressed) data size */
+ jint32_t dsize; /* Size of the node's data. (after decompression) */
+ uint8_t compr; /* Compression algorithm used */
+ uint8_t usercompr; /* Compression algorithm requested by the user */
+ jint16_t flags; /* See JFFS2_INO_FLAG_* */
+ jint32_t data_crc; /* CRC for the (compressed) data. */
+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */
+ uint8_t data[0];
+};
+
+struct jffs2_raw_xattr {
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t version;
+ uint8_t xprefix;
+ uint8_t name_len;
+ jint16_t value_len;
+ jint32_t data_crc;
+ jint32_t node_crc;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t ino; /* inode number */
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t xseqno; /* xref sequencial number */
+ jint32_t node_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_summary
+{
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t sum_num; /* number of sum entries*/
+ jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
+ jint32_t padded; /* sum of the size of padding nodes */
+ jint32_t sum_crc; /* summary information crc */
+ jint32_t node_crc; /* node crc */
+ jint32_t sum[0]; /* inode summary info */
+};
+
+union jffs2_node_union
+{
+ struct jffs2_raw_inode i;
+ struct jffs2_raw_dirent d;
+ struct jffs2_raw_xattr x;
+ struct jffs2_raw_xref r;
+ struct jffs2_raw_summary s;
+ struct jffs2_unknown_node u;
+};
+
+/* Data payload for device nodes. */
+union jffs2_device_node {
+ jint16_t old;
+ jint32_t new;
+};
+
+#endif /* __LINUX_JFFS2_H__ */
diff --git a/package/system/mtd/src/linksys_bootcount.c b/package/system/mtd/src/linksys_bootcount.c
new file mode 100644
index 0000000..95f75fe
--- /dev/null
+++ b/package/system/mtd/src/linksys_bootcount.c
@@ -0,0 +1,114 @@
+/*
+ * Linksys boot counter reset code for mtd
+ *
+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <endian.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include "mtd.h"
+
+#define BOOTCOUNT_MAGIC 0x20110811
+
+struct bootcounter {
+ uint32_t magic;
+ uint32_t count;
+ uint32_t checksum;
+};
+
+static char page[2048];
+
+int mtd_resetbc(const char *mtd)
+{
+ struct mtd_info_user mtd_info;
+ struct bootcounter *curr = (struct bootcounter *)page;
+ unsigned int i;
+ int last_count = 0;
+ int num_bc;
+ int fd;
+ int ret;
+
+ fd = mtd_check_open(mtd);
+
+ if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) {
+ fprintf(stderr, "failed to get mtd info!\n");
+ return -1;
+ }
+
+ num_bc = mtd_info.size / mtd_info.writesize;
+
+ for (i = 0; i < num_bc; i++) {
+ pread(fd, curr, sizeof(*curr), i * mtd_info.writesize);
+
+ if (curr->magic != BOOTCOUNT_MAGIC && curr->magic != 0xffffffff) {
+ fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic);
+ goto out;
+ }
+
+ if (curr->magic == 0xffffffff)
+ break;
+
+ last_count = curr->count;
+ }
+
+ /* no need to do writes when last boot count is already 0 */
+ if (last_count == 0)
+ goto out;
+
+
+ if (i == num_bc) {
+ struct erase_info_user erase_info;
+ erase_info.start = 0;
+ erase_info.length = mtd_info.size;
+
+ /* erase block */
+ ret = ioctl(fd, MEMERASE, &erase_info);
+ if (ret < 0) {
+ fprintf(stderr, "failed to erase block: %i\n", ret);
+ return -1;
+ }
+
+ i = 0;
+ }
+
+ memset(curr, 0xff, mtd_info.writesize);
+
+ curr->magic = BOOTCOUNT_MAGIC;
+ curr->count = 0;
+ curr->checksum = BOOTCOUNT_MAGIC;
+
+ ret = pwrite(fd, curr, mtd_info.writesize, i * mtd_info.writesize);
+ if (ret < 0)
+ fprintf(stderr, "failed to write: %i\n", ret);
+ sync();
+out:
+ close(fd);
+
+ return 0;
+}
diff --git a/package/system/mtd/src/md5.c b/package/system/mtd/src/md5.c
new file mode 100644
index 0000000..2039760
--- /dev/null
+++ b/package/system/mtd/src/md5.c
@@ -0,0 +1,307 @@
+
+
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#include <string.h>
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5_Init **
+ ** (2) Call MD5_Update on mdContext and M **
+ ** (3) Call MD5_Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+static unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+#ifdef __STDC__
+#define UL(x) x##U
+#else
+#define UL(x) x
+#endif
+
+/* The routine MD5_Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void MD5_Init (mdContext)
+MD5_CTX *mdContext;
+{
+ mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (UINT4)0x67452301;
+ mdContext->buf[1] = (UINT4)0xefcdab89;
+ mdContext->buf[2] = (UINT4)0x98badcfe;
+ mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void MD5_Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((UINT4)inLen << 3);
+ mdContext->i[1] += ((UINT4)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5_Final (hash, mdContext)
+unsigned char hash[];
+MD5_CTX *mdContext;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5_Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+ memcpy(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c **
+ ******************************** (cut) ********************************
+ */
diff --git a/package/system/mtd/src/md5.h b/package/system/mtd/src/md5.h
new file mode 100644
index 0000000..f7a0c96
--- /dev/null
+++ b/package/system/mtd/src/md5.h
@@ -0,0 +1,65 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#ifndef __MD5_INCLUDE__
+
+/* typedef a 32-bit type */
+#ifdef _LP64
+typedef unsigned int UINT4;
+typedef int INT4;
+#else
+typedef unsigned long UINT4;
+typedef long INT4;
+#endif
+#define _UINT4_T
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
+ UINT4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5_Init ();
+void MD5_Update ();
+void MD5_Final ();
+
+#define __MD5_INCLUDE__
+#endif /* __MD5_INCLUDE__ */
diff --git a/package/system/mtd/src/mtd.c b/package/system/mtd/src/mtd.c
new file mode 100644
index 0000000..0247630
--- /dev/null
+++ b/package/system/mtd/src/mtd.c
@@ -0,0 +1,919 @@
+/*
+ * mtd - simple memory technology device manipulation tool
+ *
+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@dass-it.de>,
+ * Copyright (C) 2005-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * The code is based on the linux-mtd examples.
+ */
+
+#define _GNU_SOURCE
+#include <limits.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/reboot.h>
+#include <linux/reboot.h>
+#include <mtd/mtd-user.h>
+#include "fis.h"
+#include "mtd.h"
+
+#include <libubox/md5.h>
+
+#define MAX_ARGS 8
+#define JFFS2_DEFAULT_DIR "" /* directory name without /, empty means root dir */
+
+static char *buf = NULL;
+static char *imagefile = NULL;
+static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
+static int buflen = 0;
+int quiet;
+int no_erase;
+int mtdsize = 0;
+int erasesize = 0;
+int jffs2_skip_bytes=0;
+int mtdtype = 0;
+
+int mtd_open(const char *mtd, bool block)
+{
+ FILE *fp;
+ char dev[PATH_MAX];
+ int i;
+ int ret;
+ int flags = O_RDWR | O_SYNC;
+ char name[PATH_MAX];
+
+ snprintf(name, sizeof(name), "\"%s\"", mtd);
+ if ((fp = fopen("/proc/mtd", "r"))) {
+ while (fgets(dev, sizeof(dev), fp)) {
+ if (sscanf(dev, "mtd%d:", &i) && strstr(dev, name)) {
+ snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i);
+ if ((ret=open(dev, flags))<0) {
+ snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i);
+ ret=open(dev, flags);
+ }
+ fclose(fp);
+ return ret;
+ }
+ }
+ fclose(fp);
+ }
+
+ return open(mtd, flags);
+}
+
+int mtd_check_open(const char *mtd)
+{
+ struct mtd_info_user mtdInfo;
+ int fd;
+
+ fd = mtd_open(mtd, false);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ return -1;
+ }
+
+ if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
+ fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
+ close(fd);
+ return -1;
+ }
+ mtdsize = mtdInfo.size;
+ erasesize = mtdInfo.erasesize;
+ mtdtype = mtdInfo.type;
+
+ return fd;
+}
+
+int mtd_block_is_bad(int fd, int offset)
+{
+ int r = 0;
+ loff_t o = offset;
+
+ if (mtdtype == MTD_NANDFLASH)
+ {
+ r = ioctl(fd, MEMGETBADBLOCK, &o);
+ if (r < 0)
+ {
+ fprintf(stderr, "Failed to get erase block status\n");
+ exit(1);
+ }
+ }
+ return r;
+}
+
+int mtd_erase_block(int fd, int offset)
+{
+ struct erase_info_user mtdEraseInfo;
+
+ mtdEraseInfo.start = offset;
+ mtdEraseInfo.length = erasesize;
+ ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
+ if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0)
+ return -1;
+
+ return 0;
+}
+
+int mtd_write_buffer(int fd, const char *buf, int offset, int length)
+{
+ lseek(fd, offset, SEEK_SET);
+ write(fd, buf, length);
+ return 0;
+}
+
+
+static int
+image_check(int imagefd, const char *mtd)
+{
+ int ret = 1;
+ if (trx_check) {
+ ret = trx_check(imagefd, mtd, buf, &buflen);
+ }
+
+ return ret;
+}
+
+static int mtd_check(const char *mtd)
+{
+ char *next = NULL;
+ char *str = NULL;
+ int fd;
+
+ if (strchr(mtd, ':')) {
+ str = strdup(mtd);
+ mtd = str;
+ }
+
+ do {
+ next = strchr(mtd, ':');
+ if (next) {
+ *next = 0;
+ next++;
+ }
+
+ fd = mtd_check_open(mtd);
+ if (fd < 0)
+ return 0;
+
+ if (!buf)
+ buf = malloc(erasesize);
+
+ close(fd);
+ mtd = next;
+ } while (next);
+
+ if (str)
+ free(str);
+
+ return 1;
+}
+
+static int
+mtd_unlock(const char *mtd)
+{
+ struct erase_info_user mtdLockInfo;
+ char *next = NULL;
+ char *str = NULL;
+ int fd;
+
+ if (strchr(mtd, ':')) {
+ str = strdup(mtd);
+ mtd = str;
+ }
+
+ do {
+ next = strchr(mtd, ':');
+ if (next) {
+ *next = 0;
+ next++;
+ }
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Unlocking %s ...\n", mtd);
+
+ mtdLockInfo.start = 0;
+ mtdLockInfo.length = mtdsize;
+ ioctl(fd, MEMUNLOCK, &mtdLockInfo);
+ close(fd);
+ mtd = next;
+ } while (next);
+
+ if (str)
+ free(str);
+
+ return 0;
+}
+
+static int
+mtd_erase(const char *mtd)
+{
+ int fd;
+ struct erase_info_user mtdEraseInfo;
+
+ if (quiet < 2)
+ fprintf(stderr, "Erasing %s ...\n", mtd);
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ mtdEraseInfo.length = erasesize;
+
+ for (mtdEraseInfo.start = 0;
+ mtdEraseInfo.start < mtdsize;
+ mtdEraseInfo.start += erasesize) {
+ if (mtd_block_is_bad(fd, mtdEraseInfo.start)) {
+ if (!quiet)
+ fprintf(stderr, "\nSkipping bad block at 0x%x ", mtdEraseInfo.start);
+ } else {
+ ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
+ if(ioctl(fd, MEMERASE, &mtdEraseInfo))
+ fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start);
+ }
+ }
+
+ close(fd);
+ return 0;
+
+}
+
+static int
+mtd_dump(const char *mtd, int part_offset, int size)
+{
+ int ret = 0, offset = 0;
+ int fd;
+ char *buf;
+
+ if (quiet < 2)
+ fprintf(stderr, "Dumping %s ...\n", mtd);
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ return -1;
+ }
+
+ if (!size)
+ size = mtdsize;
+
+ if (part_offset)
+ lseek(fd, part_offset, SEEK_SET);
+
+ buf = malloc(erasesize);
+ if (!buf)
+ return -1;
+
+ do {
+ int len = (size > erasesize) ? (erasesize) : (size);
+ int rlen = read(fd, buf, len);
+
+ if (rlen < 0) {
+ if (errno == EINTR)
+ continue;
+ ret = -1;
+ goto out;
+ }
+ if (!rlen || rlen != len)
+ break;
+ if (mtd_block_is_bad(fd, offset)) {
+ fprintf(stderr, "skipping bad block at 0x%08x\n", offset);
+ } else {
+ size -= rlen;
+ write(1, buf, rlen);
+ }
+ offset += rlen;
+ } while (size > 0);
+
+out:
+ close(fd);
+ return ret;
+}
+
+static int
+mtd_verify(const char *mtd, char *file)
+{
+ uint32_t f_md5[4], m_md5[4];
+ struct stat s;
+ md5_ctx_t ctx;
+ int ret = 0;
+ int fd;
+
+ if (quiet < 2)
+ fprintf(stderr, "Verifying %s against %s ...\n", mtd, file);
+
+ if (stat(file, &s) || md5sum(file, f_md5) < 0) {
+ fprintf(stderr, "Failed to hash %s\n", file);
+ return -1;
+ }
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ return -1;
+ }
+
+ md5_begin(&ctx);
+ do {
+ char buf[256];
+ int len = (s.st_size > sizeof(buf)) ? (sizeof(buf)) : (s.st_size);
+ int rlen = read(fd, buf, len);
+
+ if (rlen < 0) {
+ if (errno == EINTR)
+ continue;
+ ret = -1;
+ goto out;
+ }
+ if (!rlen)
+ break;
+ md5_hash(buf, rlen, &ctx);
+ s.st_size -= rlen;
+ } while (s.st_size > 0);
+
+ md5_end(m_md5, &ctx);
+
+ fprintf(stderr, "%08x%08x%08x%08x - %s\n", m_md5[0], m_md5[1], m_md5[2], m_md5[3], mtd);
+ fprintf(stderr, "%08x%08x%08x%08x - %s\n", f_md5[0], f_md5[1], f_md5[2], f_md5[3], file);
+
+ ret = memcmp(f_md5, m_md5, sizeof(m_md5));
+ if (!ret)
+ fprintf(stderr, "Success\n");
+ else
+ fprintf(stderr, "Failed\n");
+
+out:
+ close(fd);
+ return ret;
+}
+
+static void
+indicate_writing(const char *mtd)
+{
+ if (quiet < 2)
+ fprintf(stderr, "\nWriting from %s to %s ... ", imagefile, mtd);
+
+ if (!quiet)
+ fprintf(stderr, " [ ]");
+}
+
+static int
+mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
+{
+ char *next = NULL;
+ char *str = NULL;
+ int fd, result;
+ ssize_t r, w, e;
+ ssize_t skip = 0;
+ uint32_t offset = 0;
+ int jffs2_replaced = 0;
+ int skip_bad_blocks = 0;
+
+#ifdef FIS_SUPPORT
+ static struct fis_part new_parts[MAX_ARGS];
+ static struct fis_part old_parts[MAX_ARGS];
+ int n_new = 0, n_old = 0;
+
+ if (fis_layout) {
+ const char *tmp = mtd;
+ char *word, *brkt;
+ int ret;
+
+ memset(&old_parts, 0, sizeof(old_parts));
+ memset(&new_parts, 0, sizeof(new_parts));
+
+ do {
+ next = strchr(tmp, ':');
+ if (!next)
+ next = (char *) tmp + strlen(tmp);
+
+ memcpy(old_parts[n_old].name, tmp, next - tmp);
+
+ n_old++;
+ tmp = next + 1;
+ } while(*next);
+
+ for (word = strtok_r(fis_layout, ",", &brkt);
+ word;
+ word = strtok_r(NULL, ",", &brkt)) {
+
+ tmp = strtok(word, ":");
+ strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1);
+
+ tmp = strtok(NULL, ":");
+ if (!tmp)
+ goto next;
+
+ new_parts[n_new].size = strtoul(tmp, NULL, 0);
+
+ tmp = strtok(NULL, ":");
+ if (!tmp)
+ goto next;
+
+ new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16);
+next:
+ n_new++;
+ }
+ ret = fis_validate(old_parts, n_old, new_parts, n_new);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to validate the new FIS partition table\n");
+ exit(1);
+ }
+ if (ret == 0)
+ fis_layout = NULL;
+ }
+#endif
+
+ if (strchr(mtd, ':')) {
+ str = strdup(mtd);
+ mtd = str;
+ }
+
+ r = 0;
+
+resume:
+ next = strchr(mtd, ':');
+ if (next) {
+ *next = 0;
+ next++;
+ }
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+ if (part_offset > 0) {
+ fprintf(stderr, "Seeking on mtd device '%s' to: %zu\n", mtd, part_offset);
+ lseek(fd, part_offset, SEEK_SET);
+ }
+
+ indicate_writing(mtd);
+
+ w = e = 0;
+ for (;;) {
+ /* buffer may contain data already (from trx check or last mtd partition write attempt) */
+ while (buflen < erasesize) {
+ r = read(imagefd, buf + buflen, erasesize - buflen);
+ if (r < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ else {
+ perror("read");
+ break;
+ }
+ }
+
+ if (r == 0)
+ break;
+
+ buflen += r;
+ }
+
+ if (buflen == 0)
+ break;
+
+ if (buflen < erasesize) {
+ /* Pad block to eraseblock size */
+ memset(&buf[buflen], 0xff, erasesize - buflen);
+ buflen = erasesize;
+ }
+
+ if (skip > 0) {
+ skip -= buflen;
+ buflen = 0;
+ if (skip <= 0)
+ indicate_writing(mtd);
+
+ continue;
+ }
+
+ if (jffs2file && w >= jffs2_skip_bytes) {
+ if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) {
+ if (!quiet)
+ fprintf(stderr, "\b\b\b ");
+ if (quiet < 2)
+ fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd);
+ /* got an EOF marker - this is the place to add some jffs2 data */
+ skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
+ jffs2_replaced = 1;
+
+ /* don't add it again */
+ jffs2file = NULL;
+
+ w += skip;
+ e += skip;
+ skip -= buflen;
+ buflen = 0;
+ offset = 0;
+ continue;
+ }
+ /* no EOF marker, make sure we figure out the last inode number
+ * before appending some data */
+ mtd_parse_jffs2data(buf, jffs2dir);
+ }
+
+ /* need to erase the next block before writing data to it */
+ if(!no_erase)
+ {
+ while (w + buflen > e - skip_bad_blocks) {
+ if (!quiet)
+ fprintf(stderr, "\b\b\b[e]");
+
+ if (mtd_block_is_bad(fd, e)) {
+ if (!quiet)
+ fprintf(stderr, "\nSkipping bad block at 0x%08zx ", e);
+
+ skip_bad_blocks += erasesize;
+ e += erasesize;
+
+ // Move the file pointer along over the bad block.
+ lseek(fd, erasesize, SEEK_CUR);
+ continue;
+ }
+
+ if (mtd_erase_block(fd, e) < 0) {
+ if (next) {
+ if (w < e) {
+ write(fd, buf + offset, e - w);
+ offset = e - w;
+ }
+ w = 0;
+ e = 0;
+ close(fd);
+ mtd = next;
+ fprintf(stderr, "\b\b\b \n");
+ goto resume;
+ } else {
+ fprintf(stderr, "Failed to erase block\n");
+ exit(1);
+ }
+ }
+
+ /* erase the chunk */
+ e += erasesize;
+ }
+ }
+
+ if (!quiet)
+ fprintf(stderr, "\b\b\b[w]");
+
+ if ((result = write(fd, buf + offset, buflen)) < buflen) {
+ if (result < 0) {
+ fprintf(stderr, "Error writing image.\n");
+ exit(1);
+ } else {
+ fprintf(stderr, "Insufficient space.\n");
+ exit(1);
+ }
+ }
+ w += buflen;
+
+ buflen = 0;
+ offset = 0;
+ }
+
+ if (jffs2_replaced && trx_fixup) {
+ trx_fixup(fd, mtd);
+ }
+
+ if (!quiet)
+ fprintf(stderr, "\b\b\b\b ");
+
+ if (quiet < 2)
+ fprintf(stderr, "\n");
+
+#ifdef FIS_SUPPORT
+ if (fis_layout) {
+ if (fis_remap(old_parts, n_old, new_parts, n_new) < 0)
+ fprintf(stderr, "Failed to update the FIS partition table\n");
+ }
+#endif
+
+ close(fd);
+ return 0;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <device>[:<device>...]\n\n"
+ "The device is in the format of mtdX (eg: mtd4) or its label.\n"
+ "mtd recognizes these commands:\n"
+ " unlock unlock the device\n"
+ " refresh refresh mtd partition\n"
+ " erase erase all data on device\n"
+ " verify <imagefile>|- verify <imagefile> (use - for stdin) to device\n"
+ " write <imagefile>|- write <imagefile> (use - for stdin) to device\n"
+ " jffs2write <file> append <file> to the jffs2 partition on the device\n");
+ if (mtd_resetbc) {
+ fprintf(stderr,
+ " resetbc <device> reset the uboot boot counter\n");
+ }
+ if (mtd_fixtrx) {
+ fprintf(stderr,
+ " fixtrx fix the checksum in a trx header on first boot\n");
+ }
+ if (mtd_fixseama) {
+ fprintf(stderr,
+ " fixseama fix the checksum in a seama header on first boot\n");
+ }
+ fprintf(stderr,
+ "Following options are available:\n"
+ " -q quiet mode (once: no [w] on writing,\n"
+ " twice: no status messages)\n"
+ " -n write without first erasing the blocks\n"
+ " -r reboot after successful command\n"
+ " -f force write without trx checks\n"
+ " -e <device> erase <device> before executing the command\n"
+ " -d <name> directory for jffs2write, defaults to \"tmp\"\n"
+ " -j <name> integrate <file> into jffs2 data when writing an image\n"
+ " -s <number> skip the first n bytes when appending data to the jffs2 partiton, defaults to \"0\"\n"
+ " -p write beginning at partition offset\n"
+ " -l <length> the length of data that we want to dump\n");
+ if (mtd_fixtrx) {
+ fprintf(stderr,
+ " -o offset offset of the image header in the partition(for fixtrx)\n");
+ }
+ fprintf(stderr,
+#ifdef FIS_SUPPORT
+ " -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
+ " alter the fis partition table to create new partitions replacing\n"
+ " the partitions provided as argument to the write command\n"
+ " (only valid together with the write command)\n"
+#endif
+ "\n"
+ "Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n"
+ " mtd -r write linux.trx linux\n\n");
+ exit(1);
+}
+
+static void do_reboot(void)
+{
+ fprintf(stderr, "Rebooting ...\n");
+ fflush(stderr);
+
+ /* try regular reboot method first */
+ system("/sbin/reboot");
+ sleep(2);
+
+ /* if we're still alive at this point, force the kernel to reboot */
+ syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL);
+}
+
+int main (int argc, char **argv)
+{
+ int ch, i, boot, imagefd = 0, force, unlocked;
+ char *erase[MAX_ARGS], *device = NULL;
+ char *fis_layout = NULL;
+ size_t offset = 0, part_offset = 0, dump_len = 0;
+ enum {
+ CMD_ERASE,
+ CMD_WRITE,
+ CMD_UNLOCK,
+ CMD_JFFS2WRITE,
+ CMD_FIXTRX,
+ CMD_FIXSEAMA,
+ CMD_VERIFY,
+ CMD_DUMP,
+ CMD_RESETBC,
+ } cmd = -1;
+
+ erase[0] = NULL;
+ boot = 0;
+ force = 0;
+ buflen = 0;
+ quiet = 0;
+ no_erase = 0;
+
+ while ((ch = getopt(argc, argv,
+#ifdef FIS_SUPPORT
+ "F:"
+#endif
+ "frnqe:d:s:j:p:o:l:")) != -1)
+ switch (ch) {
+ case 'f':
+ force = 1;
+ break;
+ case 'r':
+ boot = 1;
+ break;
+ case 'n':
+ no_erase = 1;
+ break;
+ case 'j':
+ jffs2file = optarg;
+ break;
+ case 's':
+ errno = 0;
+ jffs2_skip_bytes = strtoul(optarg, 0, 0);
+ if (errno) {
+ fprintf(stderr, "-s: illegal numeric string\n");
+ usage();
+ }
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case 'e':
+ i = 0;
+ while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS))
+ i++;
+
+ erase[i++] = optarg;
+ erase[i] = NULL;
+ break;
+ case 'd':
+ jffs2dir = optarg;
+ break;
+ case 'p':
+ errno = 0;
+ part_offset = strtoul(optarg, 0, 0);
+ if (errno) {
+ fprintf(stderr, "-p: illegal numeric string\n");
+ usage();
+ }
+ break;
+ case 'l':
+ errno = 0;
+ dump_len = strtoul(optarg, 0, 0);
+ if (errno) {
+ fprintf(stderr, "-l: illegal numeric string\n");
+ usage();
+ }
+ break;
+ case 'o':
+ errno = 0;
+ offset = strtoul(optarg, 0, 0);
+ if (errno) {
+ fprintf(stderr, "-o: illegal numeric string\n");
+ usage();
+ }
+ break;
+#ifdef FIS_SUPPORT
+ case 'F':
+ fis_layout = optarg;
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ usage();
+
+ if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) {
+ cmd = CMD_UNLOCK;
+ device = argv[1];
+ } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
+ cmd = CMD_ERASE;
+ device = argv[1];
+ } else if (((strcmp(argv[0], "resetbc") == 0) && (argc == 2)) && mtd_resetbc) {
+ cmd = CMD_RESETBC;
+ device = argv[1];
+ } else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) {
+ cmd = CMD_FIXTRX;
+ device = argv[1];
+ } else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
+ cmd = CMD_FIXSEAMA;
+ device = argv[1];
+ } else if ((strcmp(argv[0], "verify") == 0) && (argc == 3)) {
+ cmd = CMD_VERIFY;
+ imagefile = argv[1];
+ device = argv[2];
+ } else if ((strcmp(argv[0], "dump") == 0) && (argc == 2)) {
+ cmd = CMD_DUMP;
+ device = argv[1];
+ } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
+ cmd = CMD_WRITE;
+ device = argv[2];
+
+ if (strcmp(argv[1], "-") == 0) {
+ imagefile = "<stdin>";
+ imagefd = 0;
+ } else {
+ imagefile = argv[1];
+ if ((imagefd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "Couldn't open image file: %s!\n", imagefile);
+ exit(1);
+ }
+ }
+
+ if (!mtd_check(device)) {
+ fprintf(stderr, "Can't open device for writing!\n");
+ exit(1);
+ }
+ /* check trx file before erasing or writing anything */
+ if (!image_check(imagefd, device) && !force) {
+ fprintf(stderr, "Image check failed.\n");
+ exit(1);
+ }
+ } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) {
+ cmd = CMD_JFFS2WRITE;
+ device = argv[2];
+
+ imagefile = argv[1];
+ if (!mtd_check(device)) {
+ fprintf(stderr, "Can't open device for writing!\n");
+ exit(1);
+ }
+ } else {
+ usage();
+ }
+
+ sync();
+
+ i = 0;
+ unlocked = 0;
+ while (erase[i] != NULL) {
+ mtd_unlock(erase[i]);
+ mtd_erase(erase[i]);
+ if (strcmp(erase[i], device) == 0)
+ unlocked = 1;
+ i++;
+ }
+
+ switch (cmd) {
+ case CMD_UNLOCK:
+ if (!unlocked)
+ mtd_unlock(device);
+ break;
+ case CMD_VERIFY:
+ mtd_verify(device, imagefile);
+ break;
+ case CMD_DUMP:
+ mtd_dump(device, offset, dump_len);
+ break;
+ case CMD_ERASE:
+ if (!unlocked)
+ mtd_unlock(device);
+ mtd_erase(device);
+ break;
+ case CMD_WRITE:
+ if (!unlocked)
+ mtd_unlock(device);
+ mtd_write(imagefd, device, fis_layout, part_offset);
+ break;
+ case CMD_JFFS2WRITE:
+ if (!unlocked)
+ mtd_unlock(device);
+ mtd_write_jffs2(device, imagefile, jffs2dir);
+ break;
+ case CMD_FIXTRX:
+ if (mtd_fixtrx) {
+ mtd_fixtrx(device, offset);
+ }
+ case CMD_RESETBC:
+ if (mtd_resetbc) {
+ mtd_resetbc(device);
+ }
+ case CMD_FIXSEAMA:
+ if (mtd_fixseama)
+ mtd_fixseama(device, 0);
+ break;
+ }
+
+ sync();
+
+ if (boot)
+ do_reboot();
+
+ return 0;
+}
diff --git a/package/system/mtd/src/mtd.h b/package/system/mtd/src/mtd.h
new file mode 100644
index 0000000..fb37b8b
--- /dev/null
+++ b/package/system/mtd/src/mtd.h
@@ -0,0 +1,31 @@
+#ifndef __mtd_h
+#define __mtd_h
+
+#include <stdbool.h>
+
+#ifdef target_brcm47xx
+#define target_brcm 1
+#endif
+
+#define JFFS2_EOF "\xde\xad\xc0\xde"
+
+extern int quiet;
+extern int mtdsize;
+extern int erasesize;
+
+extern int mtd_open(const char *mtd, bool block);
+extern int mtd_check_open(const char *mtd);
+extern int mtd_block_is_bad(int fd, int offset);
+extern int mtd_erase_block(int fd, int offset);
+extern int mtd_write_buffer(int fd, const char *buf, int offset, int length);
+extern int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir);
+extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename);
+extern void mtd_parse_jffs2data(const char *buf, const char *dir);
+
+/* target specific functions */
+extern int trx_fixup(int fd, const char *name) __attribute__ ((weak));
+extern int trx_check(int imagefd, const char *mtd, char *buf, int *len) __attribute__ ((weak));
+extern int mtd_fixtrx(const char *mtd, size_t offset) __attribute__ ((weak));
+extern int mtd_fixseama(const char *mtd, size_t offset) __attribute__ ((weak));
+extern int mtd_resetbc(const char *mtd) __attribute__ ((weak));
+#endif /* __mtd_h */
diff --git a/package/system/mtd/src/seama.c b/package/system/mtd/src/seama.c
new file mode 100644
index 0000000..b0c8bf3
--- /dev/null
+++ b/package/system/mtd/src/seama.c
@@ -0,0 +1,179 @@
+/*
+ * seama.c
+ *
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the trx fixup code:
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "seama.h"
+#include "md5.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X) ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X) (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+int
+seama_fix_md5(char *buf, size_t len)
+{
+ struct seama_hdr *shdr;
+ char *data;
+ size_t msize;
+ size_t isize;
+ MD5_CTX ctx;
+ unsigned char digest[16];
+ int i;
+
+ if (len < sizeof(struct seama_hdr))
+ return -1;
+
+ shdr = (struct seama_hdr *) buf;
+ if (shdr->magic != htonl(SEAMA_MAGIC)) {
+ fprintf(stderr, "no SEAMA header found\n");
+ return -1;
+ }
+
+ isize = ntohl(shdr->size);
+ msize = ntohs(shdr->metasize);
+ if (isize == 0) {
+ /* the image contains no checksum */
+ return -1;
+ }
+
+ len -= sizeof(struct seama_hdr) + sizeof(digest) + msize;
+ if (isize > len)
+ isize = len;
+
+ data = buf + sizeof(struct seama_hdr) + sizeof(digest) + msize;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, data, isize);
+ MD5_Final(digest, &ctx);
+
+ if (!memcmp(digest, &buf[sizeof(struct seama_hdr)], sizeof(digest))) {
+ if (quiet < 2)
+ fprintf(stderr, "the header is fixed already\n");
+ return -1;
+ }
+
+ if (quiet < 2) {
+ fprintf(stderr, "new size:%u, new MD5: ", isize);
+ for (i = 0; i < sizeof(digest); i++)
+ fprintf(stderr, "%02x", digest[i]);
+
+ fprintf(stderr, "\n");
+ }
+
+ /* update the size in the image */
+ shdr->size = htonl(isize);
+
+ /* update the checksum in the image */
+ for (i = 0; i < sizeof(digest); i++)
+ buf[sizeof(struct seama_hdr) + i] = digest[i];
+
+ return 0;
+}
+
+int
+mtd_fixseama(const char *mtd, size_t offset)
+{
+ int fd;
+ char *buf;
+ ssize_t res;
+ size_t block_offset;
+
+ if (quiet < 2)
+ fprintf(stderr, "Trying to fix SEAMA header in %s at 0x%x...\n",
+ mtd, offset);
+
+ block_offset = offset & ~(erasesize - 1);
+ offset -= block_offset;
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ if (block_offset + erasesize > mtdsize) {
+ fprintf(stderr, "Offset too large, device size 0x%x\n",
+ mtdsize);
+ exit(1);
+ }
+
+ buf = malloc(mtdsize);
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ res = pread(fd, buf, mtdsize, block_offset);
+ if (res != mtdsize) {
+ perror("pread");
+ exit(1);
+ }
+
+ if (seama_fix_md5(buf, mtdsize))
+ goto out;
+
+ if (mtd_erase_block(fd, block_offset)) {
+ fprintf(stderr, "Can't erease block at 0x%x (%s)\n",
+ block_offset, strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Rewriting block at 0x%x\n", block_offset);
+
+ if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+ fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Done.\n");
+
+out:
+ close (fd);
+ sync();
+
+ return 0;
+}
+
diff --git a/package/system/mtd/src/seama.h b/package/system/mtd/src/seama.h
new file mode 100644
index 0000000..02683b6
--- /dev/null
+++ b/package/system/mtd/src/seama.h
@@ -0,0 +1,108 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * (SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ * Created by David Hsieh <david_hsieh@alphanetworks.com>
+ * Copyright (C) 2008-2009 Alpha Networks, Inc.
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either'
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The GNU C Library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ */
+
+#ifndef __SEAMA_HEADER_FILE__
+#define __SEAMA_HEADER_FILE__
+
+#include <stdint.h>
+
+#define SEAMA_MAGIC 0x5EA3A417
+
+/*
+ * SEAMA looks like the following map.
+ * All the data of the header should be in network byte order.
+ *
+ * +-------------+-------------+------------
+ * | SEAMA magic | ^
+ * +-------------+-------------+ |
+ * | reserved | meta size | |
+ * +-------------+-------------+ header
+ * | image size (0 bytes) | |
+ * +-------------+-------------+ |
+ * ~ Meta data ~ v
+ * +-------------+-------------+------------
+ * | SEAMA magic | ^ ^
+ * +-------------+-------------+ | |
+ * | reserved | meta size | | |
+ * +-------------+-------------+ | |
+ * | image size | | |
+ * +-------------+-------------+ header |
+ * | | | |
+ * | 16 bytes of MD5 digest | | |
+ * | | | |
+ * | | | |
+ * +-------------+-------------+ | |
+ * ~ Meta data ~ v |
+ * +-------------+-------------+------- |
+ * | | |
+ * | Image of the 1st entity | |
+ * ~ ~ 1st entity
+ * | | |
+ * | | v
+ * +-------------+-------------+-------------
+ * | SEAMA magic | ^ ^
+ * +-------------+-------------+ | |
+ * | reserved | meta size | | |
+ * +-------------+-------------+ | |
+ * | image size | | |
+ * +-------------+-------------+ header |
+ * | | | |
+ * | 16 bytes of MD5 digest | | |
+ * | | | |
+ * | | | |
+ * +-------------+-------------+ | |
+ * ~ Meta data ~ v |
+ * +-------------+-------------+------- |
+ * | | |
+ * | Image of the 2nd entity | |
+ * ~ ~ 2nd entity
+ * | | |
+ * | | v
+ * +-------------+-------------+-------------
+ */
+
+
+/*
+ * SEAMA header
+ *
+ * |<-------- 32 bits -------->|
+ * +-------------+-------------+
+ * | SEAMA magic |
+ * +-------------+-------------+
+ * | reserved | meta size |
+ * +-------------+-------------+
+ * | image size |
+ * +-------------+-------------+
+ */
+/* seama header */
+typedef struct seama_hdr seamahdr_t;
+struct seama_hdr
+{
+ uint32_t magic; /* should always be SEAMA_MAGIC. */
+ uint16_t reserved; /* reserved for */
+ uint16_t metasize; /* size of the META data */
+ uint32_t size; /* size of the image */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/package/system/mtd/src/trx.c b/package/system/mtd/src/trx.c
new file mode 100644
index 0000000..245ee76
--- /dev/null
+++ b/package/system/mtd/src/trx.c
@@ -0,0 +1,223 @@
+/*
+ * trx.c
+ *
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <endian.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "crc32.h"
+
+#define TRX_MAGIC 0x30524448 /* "HDR0" */
+struct trx_header {
+ uint32_t magic; /* "HDR0" */
+ uint32_t len; /* Length of file including header */
+ uint32_t crc32; /* 32-bit CRC from flag_version to end of file */
+ uint32_t flag_version; /* 0:15 flags, 16:31 version */
+ uint32_t offsets[3]; /* Offsets of partitions from start of header */
+};
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X) ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X) (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+int
+trx_fixup(int fd, const char *name)
+{
+ struct mtd_info_user mtdInfo;
+ unsigned long len;
+ struct trx_header *trx;
+ void *ptr, *scan;
+ int bfd;
+
+ if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
+ fprintf(stderr, "Failed to get mtd info\n");
+ goto err;
+ }
+
+ len = mtdInfo.size;
+ if (mtdInfo.size <= 0) {
+ fprintf(stderr, "Invalid MTD device size\n");
+ goto err;
+ }
+
+ bfd = mtd_open(name, true);
+ ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
+ if (!ptr || (ptr == (void *) -1)) {
+ perror("mmap");
+ goto err1;
+ }
+
+ trx = ptr;
+ if (trx->magic != TRX_MAGIC) {
+ fprintf(stderr, "TRX header not found\n");
+ goto err;
+ }
+
+ scan = ptr + offsetof(struct trx_header, flag_version);
+ trx->crc32 = crc32buf(scan, trx->len - (scan - ptr));
+ msync(ptr, sizeof(struct trx_header), MS_SYNC|MS_INVALIDATE);
+ munmap(ptr, len);
+ close(bfd);
+ return 0;
+
+err1:
+ close(bfd);
+err:
+ fprintf(stderr, "Error fixing up TRX header\n");
+ return -1;
+}
+
+#ifndef target_ar71xx
+int
+trx_check(int imagefd, const char *mtd, char *buf, int *len)
+{
+ const struct trx_header *trx = (const struct trx_header *) buf;
+ int fd;
+
+ if (strcmp(mtd, "firmware") != 0)
+ return 1;
+
+ *len = read(imagefd, buf, 32);
+ if (*len < 32) {
+ fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
+ return 0;
+ }
+
+ if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) {
+ if (quiet < 2) {
+ fprintf(stderr, "Bad trx header\n");
+ fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
+ "Please specify the correct file or use -f to force.\n");
+ }
+ return 0;
+ }
+
+ /* check if image fits to mtd device */
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ if(mtdsize < trx->len) {
+ fprintf(stderr, "Image too big for partition: %s\n", mtd);
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+ return 1;
+}
+#endif
+
+int
+mtd_fixtrx(const char *mtd, size_t offset)
+{
+ int fd;
+ struct trx_header *trx;
+ char *buf;
+ ssize_t res;
+ size_t block_offset;
+
+ if (quiet < 2)
+ fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
+
+ fd = mtd_check_open(mtd);
+ if(fd < 0) {
+ fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+ exit(1);
+ }
+
+ block_offset = offset & ~(erasesize - 1);
+ offset -= block_offset;
+
+ if (block_offset + erasesize > mtdsize) {
+ fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
+ exit(1);
+ }
+
+ buf = malloc(erasesize);
+ if (!buf) {
+ perror("malloc");
+ exit(1);
+ }
+
+ res = pread(fd, buf, erasesize, block_offset);
+ if (res != erasesize) {
+ perror("pread");
+ exit(1);
+ }
+
+ trx = (struct trx_header *) (buf + offset);
+ if (trx->magic != STORE32_LE(0x30524448)) {
+ fprintf(stderr, "No trx magic found\n");
+ exit(1);
+ }
+
+ if (trx->len == STORE32_LE(erasesize - offset)) {
+ if (quiet < 2)
+ fprintf(stderr, "Header already fixed, exiting\n");
+ close(fd);
+ return 0;
+ }
+
+ trx->len = STORE32_LE(erasesize - offset);
+
+ trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, erasesize - offset - 3*4));
+ if (mtd_erase_block(fd, block_offset)) {
+ fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32);
+
+ if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+ fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+ exit(1);
+ }
+
+ if (quiet < 2)
+ fprintf(stderr, "Done.\n");
+
+ close (fd);
+ sync();
+ return 0;
+
+}
+
diff --git a/package/system/opkg/Makefile b/package/system/opkg/Makefile
new file mode 100644
index 0000000..cb8fb74
--- /dev/null
+++ b/package/system/opkg/Makefile
@@ -0,0 +1,164 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/version.mk
+include $(INCLUDE_DIR)/feeds.mk
+
+PKG_NAME:=opkg
+PKG_REV:=9c97d5ecd795709c8584e972bfdf3aee3a5b846d
+PKG_VERSION:=$(PKG_REV)
+PKG_RELEASE:=10
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_SUBDIR:=opkg-$(PKG_VERSION)
+PKG_SOURCE_URL:=http://git.yoctoproject.org/git/opkg
+PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_FIXUP:=autoreconf
+PKG_REMOVE_FILES = autogen.sh aclocal.m4
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jow@openwrt.org>
+
+PKG_CONFIG_DEPENDS := CONFIG_SIGNED_PACKAGES
+
+PKG_BUILD_PARALLEL:=1
+HOST_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/opkg/Default
+ SECTION:=base
+ CATEGORY:=Base system
+ TITLE:=opkg package manager
+ URL:=http://wiki.openmoko.org/wiki/Opkg
+endef
+
+define Package/opkg/Default/description
+ Lightweight package management system
+ opkg is the opkg Package Management System, for handling
+ installation and removal of packages on a system. It can
+ recursively follow dependencies and download all packages
+ necessary to install a particular package.
+
+ opkg knows how to install both .ipk and .deb packages.
+endef
+
+define Package/opkg
+ $(call Package/opkg/Default)
+ VARIANT:=unsigned
+endef
+
+define Package/opkg/description
+ $(call Package/opkg/Default/description)
+endef
+
+define Package/opkg/conffiles
+/etc/opkg.conf
+/etc/opkg/keys/
+/etc/opkg/customfeeds.conf
+endef
+
+
+define Package/opkg-smime
+ $(call Package/opkg/Default)
+ TITLE+= (with S/MIME signature support)
+ DEPENDS+=+PACKAGE_opkg-smime:libopenssl
+ VARIANT:=smime
+endef
+
+define Package/opkg-smime/description
+ $(call Package/opkg/Default/description)
+
+ This package allows the Package index to be verified with S/MIME.
+endef
+
+Package/opkg-smime/conffiles = $(Package/opkg/conffiles)
+
+TARGET_CFLAGS += $(if $(CONFIG_GCC_VERSION_4_3)$(CONFIG_GCC_VERSION_4_4),-Wno-array-bounds)
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+EXTRA_CFLAGS += $(TARGET_CPPFLAGS)
+
+CONFIGURE_ARGS += \
+ --disable-curl \
+ --disable-gpg \
+ --enable-sha256 \
+ --with-opkgetcdir=/etc \
+ --with-opkglockfile=/var/lock/opkg.lock
+
+ifeq ($(BUILD_VARIANT),smime)
+ CONFIGURE_ARGS += --enable-openssl --disable-usign
+else
+ ifndef CONFIG_SIGNED_PACKAGES
+ CONFIGURE_ARGS += --disable-usign
+ endif
+endif
+
+MAKE_FLAGS = \
+ CC="$(TARGET_CC)" \
+ DESTDIR="$(PKG_INSTALL_DIR)" \
+ HOST_CPU="$(PKGARCH)" \
+ LDFLAGS="-Wl,--gc-sections" \
+
+define Package/opkg/Default/install
+ $(INSTALL_DIR) $(1)/usr/lib/opkg
+ $(INSTALL_DIR) $(1)/bin
+ $(INSTALL_DIR) $(1)/etc/opkg
+ $(INSTALL_DIR) $(1)/etc/uci-defaults
+ $(INSTALL_DATA) ./files/customfeeds.conf $(1)/etc/opkg/customfeeds.conf
+ $(INSTALL_DATA) ./files/opkg$(2).conf $(1)/etc/opkg.conf
+ $(call FeedSourcesAppend,$(1)/etc/opkg/distfeeds.conf)
+ $(VERSION_SED) $(1)/etc/opkg/distfeeds.conf
+ $(INSTALL_BIN) ./files/20_migrate-feeds $(1)/etc/uci-defaults/
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/opkg-cl $(1)/bin/opkg
+endef
+
+define Package/opkg/install
+ $(call Package/opkg/Default/install,$(1),)
+ ifneq ($(CONFIG_SIGNED_PACKAGES),)
+ echo "option check_signature 1" >> $(1)/etc/opkg.conf
+ endif
+ mkdir $(1)/usr/sbin
+ $(INSTALL_BIN) ./files/opkg-key $(1)/usr/sbin/
+endef
+
+define Package/opkg-smime/install
+ $(call Package/opkg/Default/install,$(1),-smime)
+ $(INSTALL_DIR) $(1)/etc/ssl/certs
+ $(if $(CONFIG_OPKGSMIME_CERT),$(INSTALL_DATA) $(call qstrip,$(CONFIG_OPKGSMIME_CERT)) $(1)/etc/ssl/certs/opkg.pem,)
+endef
+
+define Build/InstallDev
+ mkdir -p $(1)/usr/include
+ $(CP) $(PKG_INSTALL_DIR)/usr/include/libopkg $(1)/usr/include/
+endef
+
+
+HOST_CONFIGURE_ARGS+= \
+ --disable-curl \
+ --disable-gpg \
+ --enable-sha256 \
+ --with-opkgetcdir=/etc \
+ --with-opkglockfile=/tmp/opkg.lock
+
+define Host/Compile
+ +$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) CC="$(HOSTCC)" all
+endef
+
+define Host/Install
+ $(INSTALL_BIN) $(HOST_BUILD_DIR)/src/opkg-cl $(STAGING_DIR_HOST)/bin/opkg
+endef
+
+$(eval $(call BuildPackage,opkg))
+$(eval $(call BuildPackage,opkg-smime))
+$(eval $(call HostBuild))
diff --git a/package/system/opkg/files/20_migrate-feeds b/package/system/opkg/files/20_migrate-feeds
new file mode 100644
index 0000000..38cc57c
--- /dev/null
+++ b/package/system/opkg/files/20_migrate-feeds
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+[ -f /etc/opkg.conf ] && grep -q "src\/" /etc/opkg.conf || exit 0
+
+echo -e "# Old feeds from previous image\n# Uncomment to reenable\n" >> /etc/opkg/customfeeds.conf
+sed -n "s/.*\(src\/.*\)/# \1/p" /etc/opkg.conf >> /etc/opkg/customfeeds.conf
+sed -i "/.*src\/.*/d" /etc/opkg.conf
+
+exit 0
diff --git a/package/system/opkg/files/customfeeds.conf b/package/system/opkg/files/customfeeds.conf
new file mode 100644
index 0000000..f130113
--- /dev/null
+++ b/package/system/opkg/files/customfeeds.conf
@@ -0,0 +1,3 @@
+# add your custom package feeds here
+#
+# src/gz example_feed_name http://www.example.com/path/to/files
diff --git a/package/system/opkg/files/opkg-key b/package/system/opkg/files/opkg-key
new file mode 100755
index 0000000..ae5e8a4
--- /dev/null
+++ b/package/system/opkg/files/opkg-key
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+usage() {
+ cat <<EOF
+Usage: $0 <command> <arguments...>
+Commands:
+ add <file>: Add keyfile <file> to opkg trusted keys
+ remove <file>: Remove keyfile matching <file> from opkg trusted keys
+ verify <sigfile> <list>: Check list file <list> against signature file <sigfile>
+
+EOF
+ exit 1
+}
+
+opkg_key_verify() {
+ local sigfile="$1"
+ local msgfile="$2"
+
+ (
+ zcat "$msgfile" 2>/dev/null ||
+ cat "$msgfile" 2>/dev/null
+ ) | usign -V -P /etc/opkg/keys -q -x "$sigfile" -m -
+}
+
+opkg_key_add() {
+ local key="$1"
+ [ -n "$key" ] || usage
+ [ -f "$key" ] || echo "Cannot open file $1"
+ local fingerprint="$(usign -F -p "$key")"
+ mkdir -p "/etc/opkg/keys"
+ cp "$key" "/etc/opkg/keys/$fingerprint"
+}
+
+opkg_key_remove() {
+ local key="$1"
+ [ -n "$key" ] || usage
+ [ -f "$key" ] || echo "Cannot open file $1"
+ local fingerprint="$(usign -F -p "$key")"
+ rm -f "/etc/opkg/keys/$fingerprint"
+}
+
+case "$1" in
+ add)
+ shift
+ opkg_key_add "$@"
+ ;;
+ remove)
+ shift
+ opkg_key_remove "$@"
+ ;;
+ verify)
+ shift
+ opkg_key_verify "$@"
+ ;;
+ *) usage ;;
+esac
diff --git a/package/system/opkg/files/opkg-smime.conf b/package/system/opkg/files/opkg-smime.conf
new file mode 100644
index 0000000..fd2cade
--- /dev/null
+++ b/package/system/opkg/files/opkg-smime.conf
@@ -0,0 +1,6 @@
+dest root /
+dest ram /tmp
+lists_dir ext /var/opkg-lists
+option overlay_root /overlay
+option check_signature 1
+option signature_ca_file /etc/ssl/certs/opkg.pem
diff --git a/package/system/opkg/files/opkg.conf b/package/system/opkg/files/opkg.conf
new file mode 100644
index 0000000..d8d3a2d
--- /dev/null
+++ b/package/system/opkg/files/opkg.conf
@@ -0,0 +1,4 @@
+dest root /
+dest ram /tmp
+lists_dir ext /var/opkg-lists
+option overlay_root /overlay
diff --git a/package/system/opkg/patches/001-ship-pkg-m4.patch b/package/system/opkg/patches/001-ship-pkg-m4.patch
new file mode 100644
index 0000000..4ca0f88
--- /dev/null
+++ b/package/system/opkg/patches/001-ship-pkg-m4.patch
@@ -0,0 +1,168 @@
+--- /dev/null
++++ b/m4/pkg.m4
+@@ -0,0 +1,157 @@
++# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
++#
++# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++#
++# As a special exception to the GNU General Public License, if you
++# distribute this file as part of a program that contains a
++# configuration script generated by Autoconf, you may include it under
++# the same distribution terms that you use for the rest of that program.
++
++# PKG_PROG_PKG_CONFIG([MIN-VERSION])
++# ----------------------------------
++AC_DEFUN([PKG_PROG_PKG_CONFIG],
++[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
++m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
++AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
++if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
++ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
++fi
++if test -n "$PKG_CONFIG"; then
++ _pkg_min_version=m4_default([$1], [0.9.0])
++ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
++ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
++ AC_MSG_RESULT([yes])
++ else
++ AC_MSG_RESULT([no])
++ PKG_CONFIG=""
++ fi
++
++fi[]dnl
++])# PKG_PROG_PKG_CONFIG
++
++# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
++#
++# Check to see whether a particular set of modules exists. Similar
++# to PKG_CHECK_MODULES(), but does not set variables or print errors.
++#
++#
++# Similar to PKG_CHECK_MODULES, make sure that the first instance of
++# this or PKG_CHECK_MODULES is called, or make sure to call
++# PKG_CHECK_EXISTS manually
++# --------------------------------------------------------------
++AC_DEFUN([PKG_CHECK_EXISTS],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
++if test -n "$PKG_CONFIG" && \
++ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
++ m4_ifval([$2], [$2], [:])
++m4_ifvaln([$3], [else
++ $3])dnl
++fi])
++
++
++# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
++# ---------------------------------------------
++m4_define([_PKG_CONFIG],
++[if test -n "$PKG_CONFIG"; then
++ if test -n "$$1"; then
++ pkg_cv_[]$1="$$1"
++ else
++ PKG_CHECK_EXISTS([$3],
++ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
++ [pkg_failed=yes])
++ fi
++else
++ pkg_failed=untried
++fi[]dnl
++])# _PKG_CONFIG
++
++# _PKG_SHORT_ERRORS_SUPPORTED
++# -----------------------------
++AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
++if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
++ _pkg_short_errors_supported=yes
++else
++ _pkg_short_errors_supported=no
++fi[]dnl
++])# _PKG_SHORT_ERRORS_SUPPORTED
++
++
++# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
++# [ACTION-IF-NOT-FOUND])
++#
++#
++# Note that if there is a possibility the first call to
++# PKG_CHECK_MODULES might not happen, you should be sure to include an
++# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
++#
++#
++# --------------------------------------------------------------
++AC_DEFUN([PKG_CHECK_MODULES],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
++AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
++AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
++
++pkg_failed=no
++AC_MSG_CHECKING([for $1])
++
++_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
++_PKG_CONFIG([$1][_LIBS], [libs], [$2])
++
++m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
++and $1[]_LIBS to avoid the need to call pkg-config.
++See the pkg-config man page for more details.])
++
++if test $pkg_failed = yes; then
++ _PKG_SHORT_ERRORS_SUPPORTED
++ if test $_pkg_short_errors_supported = yes; then
++ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
++ else
++ $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
++ fi
++ # Put the nasty error message in config.log where it belongs
++ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
++
++ ifelse([$4], , [AC_MSG_ERROR(dnl
++[Package requirements ($2) were not met:
++
++$$1_PKG_ERRORS
++
++Consider adjusting the PKG_CONFIG_PATH environment variable if you
++installed software in a non-standard prefix.
++
++_PKG_TEXT
++])],
++ [AC_MSG_RESULT([no])
++ $4])
++elif test $pkg_failed = untried; then
++ ifelse([$4], , [AC_MSG_FAILURE(dnl
++[The pkg-config script could not be found or is too old. Make sure it
++is in your PATH or set the PKG_CONFIG environment variable to the full
++path to pkg-config.
++
++_PKG_TEXT
++
++To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
++ [$4])
++else
++ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
++ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
++ AC_MSG_RESULT([yes])
++ ifelse([$3], , :, [$3])
++fi[]dnl
++])# PKG_CHECK_MODULES
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,4 +1,4 @@
+-ACLOCAL_AMFLAGS = -I shave
++ACLOCAL_AMFLAGS = -I shave -I m4
+
+ SUBDIRS = libbb libopkg src tests utils man
+
diff --git a/package/system/opkg/patches/002-no-shave.patch b/package/system/opkg/patches/002-no-shave.patch
new file mode 100644
index 0000000..313aa71
--- /dev/null
+++ b/package/system/opkg/patches/002-no-shave.patch
@@ -0,0 +1,37 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -4,7 +4,6 @@ AC_CONFIG_SRCDIR([libopkg/pkg.c])
+
+ AC_CONFIG_AUX_DIR([conf])
+ AC_CONFIG_MACRO_DIR([m4])
+-AC_CONFIG_MACRO_DIR([shave])
+
+ AM_INIT_AUTOMAKE
+ AM_CONFIG_HEADER(libopkg/config.h)
+@@ -277,9 +276,6 @@ AC_SUBST(opkgetcdir)
+ AC_SUBST(opkglockfile)
+ AC_SUBST([CLEAN_DATE])
+
+-# Setup output beautifier.
+-SHAVE_INIT([shave], [enable])
+-
+ AC_OUTPUT(
+ Makefile
+ libopkg/Makefile
+@@ -289,8 +285,6 @@ AC_OUTPUT(
+ utils/Makefile
+ utils/update-alternatives
+ libopkg.pc
+- shave/shave
+- shave/shave-libtool
+ man/Makefile
+ man/opkg-cl.1
+ man/opkg-key.1
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,4 +1,4 @@
+-ACLOCAL_AMFLAGS = -I shave -I m4
++ACLOCAL_AMFLAGS = -I m4
+
+ SUBDIRS = libbb libopkg src tests utils man
+
diff --git a/package/system/opkg/patches/004-host_cpu.patch b/package/system/opkg/patches/004-host_cpu.patch
new file mode 100644
index 0000000..d500d60
--- /dev/null
+++ b/package/system/opkg/patches/004-host_cpu.patch
@@ -0,0 +1,20 @@
+--- a/libbb/Makefile.am
++++ b/libbb/Makefile.am
+@@ -1,6 +1,6 @@
+ HOST_CPU=@host_cpu@
+ BUILD_CPU=@build_cpu@
+-ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@
++ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"$(HOST_CPU)\" -DBUILD_CPU=@build_cpu@
+
+ noinst_LTLIBRARIES = libbb.la
+
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -1,5 +1,5 @@
+-
+-AM_CFLAGS=-Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS)
++HOST_CPU=@host_cpu@
++AM_CFLAGS=-Wall -DHOST_CPU_STR=\"$(HOST_CPU)\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS)
+
+ libopkg_includedir=$(includedir)/libopkg
+ libopkg_include_HEADERS= *.h
diff --git a/package/system/opkg/patches/007-force_static.patch b/package/system/opkg/patches/007-force_static.patch
new file mode 100644
index 0000000..38cdb7a
--- /dev/null
+++ b/package/system/opkg/patches/007-force_static.patch
@@ -0,0 +1,71 @@
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -38,16 +38,10 @@
+ opkg_util_sources += sha256.c sha256.h
+ endif
+
+-lib_LTLIBRARIES = libopkg.la
+-libopkg_la_SOURCES = \
++noinst_LIBRARIES = libopkg.a
++libopkg_a_SOURCES = \
+ $(opkg_libcore_sources) \
+ $(opkg_cmd_sources) $(opkg_db_sources) \
+ $(opkg_util_sources) $(opkg_list_sources)
+
+-libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
+-
+-# make sure we only export symbols that are for public use
+-#libopkg_la_LDFLAGS = -export-symbols-regex "^opkg_.*"
+-
+-
+-
++libopkg_a_LIBADD = $(top_builddir)/libbb/libbb.a
+--- a/libbb/Makefile.am
++++ b/libbb/Makefile.am
+@@ -2,9 +2,9 @@
+ BUILD_CPU=@build_cpu@
+ ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"$(HOST_CPU)\" -DBUILD_CPU=@build_cpu@
+
+-noinst_LTLIBRARIES = libbb.la
++noinst_LIBRARIES = libbb.a
+
+-libbb_la_SOURCES = gz_open.c \
++libbb_a_SOURCES = gz_open.c \
+ libbb.h \
+ unzip.c \
+ wfopen.c \
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -4,11 +4,11 @@
+ #noinst_PROGRAMS = libopkg_test opkg_active_list_test
+ noinst_PROGRAMS = libopkg_test
+
+-#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
++#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.a $(top_builddir)/libopkg/libopkg.a
+ #opkg_hash_test_SOURCES = opkg_hash_test.c
+ #opkg_hash_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+-#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
++#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.a $(top_builddir)/libopkg/libopkg.a
+ #opkg_extract_test_SOURCES = opkg_extract_test.c
+ #opkg_extract_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+@@ -16,7 +16,7 @@
+ #opkg_active_list_test_SOURCES = opkg_active_list_test.c
+ #opkg_active_list_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+-libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.la
++libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.a $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
+ libopkg_test_SOURCE = libopkg_test.c
+ libopkg_test_LDFLAGS = -static
+
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -2,5 +2,5 @@
+ bin_PROGRAMS = opkg-cl
+
+ opkg_cl_SOURCES = opkg-cl.c
+-opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.la \
+- $(top_builddir)/libbb/libbb.la
++opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.a \
++ $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
diff --git a/package/system/opkg/patches/009-remove-upgrade-all.patch b/package/system/opkg/patches/009-remove-upgrade-all.patch
new file mode 100644
index 0000000..395a2a6
--- /dev/null
+++ b/package/system/opkg/patches/009-remove-upgrade-all.patch
@@ -0,0 +1,41 @@
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -551,18 +551,6 @@ opkg_upgrade_cmd(int argc, char **argv)
+ err = -1;
+ }
+ }
+- } else {
+- pkg_vec_t *installed = pkg_vec_alloc();
+-
+- pkg_info_preinstall_check();
+-
+- pkg_hash_fetch_all_installed(installed);
+- for (i = 0; i < installed->len; i++) {
+- pkg = installed->pkgs[i];
+- if (opkg_upgrade_pkg(pkg))
+- err = -1;
+- }
+- pkg_vec_free(installed);
+ }
+
+ if (opkg_configure_packages(NULL))
+@@ -1258,7 +1246,7 @@ opkg_print_architecture_cmd(int argc, ch
+ array for easier maintenance */
+ static opkg_cmd_t cmds[] = {
+ {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+- {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE},
++ {"upgrade", 1, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+ {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE},
+ {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
+ {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -221,7 +221,7 @@ usage()
+
+ printf("\nPackage Manipulation:\n");
+ printf("\tupdate Update list of available packages\n");
+- printf("\tupgrade Upgrade installed packages\n");
++ printf("\tupgrade <pkgs> Upgrade packages\n");
+ printf("\tinstall <pkgs> Install package(s)\n");
+ printf("\tconfigure <pkgs> Configure unpacked package(s)\n");
+ printf("\tremove <pkgs|regexp> Remove package(s)\n");
diff --git a/package/system/opkg/patches/011-old-config-location.patch b/package/system/opkg/patches/011-old-config-location.patch
new file mode 100644
index 0000000..0555926
--- /dev/null
+++ b/package/system/opkg/patches/011-old-config-location.patch
@@ -0,0 +1,12 @@
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -207,6 +207,9 @@ args_parse(int argc, char *argv[])
+ }
+ }
+
++ if(!conf->conf_file && !conf->offline_root)
++ conf->conf_file = xstrdup("/etc/opkg.conf");
++
+ if (parse_err)
+ return parse_err;
+ else
diff --git a/package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch b/package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch
new file mode 100644
index 0000000..a47ae77
--- /dev/null
+++ b/package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch
@@ -0,0 +1,23 @@
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -274,6 +274,7 @@ unpack_pkg_control_files(pkg_t *pkg)
+ while (1) {
+ char *cf_name;
+ char *cf_name_in_dest;
++ int i;
+
+ cf_name = file_read_line_alloc(conffiles_file);
+ if (cf_name == NULL) {
+@@ -282,6 +283,12 @@ unpack_pkg_control_files(pkg_t *pkg)
+ if (cf_name[0] == '\0') {
+ continue;
+ }
++ for (i = strlen(cf_name) - 1;
++ (i >= 0) && (cf_name[i] == ' ' || cf_name[i] == '\t');
++ i--
++ ) {
++ cf_name[i] = '\0';
++ }
+
+ /* Prepend dest->root_dir to conffile name.
+ Take pains to avoid multiple slashes. */
diff --git a/package/system/opkg/patches/014-errors-to-stderr.patch b/package/system/opkg/patches/014-errors-to-stderr.patch
new file mode 100644
index 0000000..f0a93a8
--- /dev/null
+++ b/package/system/opkg/patches/014-errors-to-stderr.patch
@@ -0,0 +1,15 @@
+--- a/libopkg/opkg_message.c
++++ b/libopkg/opkg_message.c
+@@ -64,10 +64,10 @@ print_error_list(void)
+ struct errlist *err = error_list_head;
+
+ if (err) {
+- printf("Collected errors:\n");
++ fprintf(stderr, "Collected errors:\n");
+ /* Here we print the errors collected and free the list */
+ while (err != NULL) {
+- printf(" * %s", err->errmsg);
++ fprintf(stderr, " * %s", err->errmsg);
+ err = err->next;
+ }
+ }
diff --git a/package/system/opkg/patches/020-avoid_getline.patch b/package/system/opkg/patches/020-avoid_getline.patch
new file mode 100644
index 0000000..8a1a8f6
--- /dev/null
+++ b/package/system/opkg/patches/020-avoid_getline.patch
@@ -0,0 +1,317 @@
+--- a/libopkg/parse_util.c
++++ b/libopkg/parse_util.c
+@@ -22,6 +22,7 @@
+ #include "libbb/libbb.h"
+
+ #include "parse_util.h"
++#include "pkg_parse.h"
+
+ int
+ is_field(const char *type, const char *line)
+@@ -86,3 +87,84 @@ parse_list(const char *raw, unsigned int
+ *count = line_count;
+ return depends;
+ }
++
++int
++parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask,
++ char **buf0, size_t buf0len)
++{
++ int ret, lineno;
++ char *buf, *nl;
++ size_t buflen;
++
++ lineno = 1;
++ ret = 0;
++
++ buflen = buf0len;
++ buf = *buf0;
++ buf[0] = '\0';
++
++ while (1) {
++ if (fgets(buf, (int)buflen, fp) == NULL) {
++ if (ferror(fp)) {
++ opkg_perror(ERROR, "fgets");
++ ret = -1;
++ } else if (strlen(*buf0) == buf0len-1) {
++ opkg_msg(ERROR, "Missing new line character"
++ " at end of file!\n");
++ parse_line(item, *buf0, mask);
++ }
++ break;
++ }
++
++ nl = strchr(buf, '\n');
++ if (nl == NULL) {
++ if (strlen(buf) < buflen-1) {
++ /*
++ * Line could be exactly buflen-1 long and
++ * missing a newline, but we won't know until
++ * fgets fails to read more data.
++ */
++ opkg_msg(ERROR, "Missing new line character"
++ " at end of file!\n");
++ parse_line(item, *buf0, mask);
++ break;
++ }
++ if (buf0len >= EXCESSIVE_LINE_LEN) {
++ opkg_msg(ERROR, "Excessively long line at "
++ "%d. Corrupt file?\n",
++ lineno);
++ ret = -1;
++ break;
++ }
++
++ /*
++ * Realloc and point buf past the data already read,
++ * at the NULL terminator inserted by fgets.
++ * |<--------------- buf0len ----------------->|
++ * | |<------- buflen ---->|
++ * |---------------------|---------------------|
++ * buf0 buf
++ */
++ buflen = buf0len +1;
++ buf0len *= 2;
++ *buf0 = xrealloc(*buf0, buf0len);
++ buf = *buf0 + buflen -2;
++
++ continue;
++ }
++
++ *nl = '\0';
++
++ lineno++;
++
++ if (parse_line(item, *buf0, mask))
++ break;
++
++ buf = *buf0;
++ buflen = buf0len;
++ buf[0] = '\0';
++ }
++
++ return ret;
++}
++
+--- a/libopkg/parse_util.h
++++ b/libopkg/parse_util.h
+@@ -22,4 +22,8 @@ int is_field(const char *type, const cha
+ char *parse_simple(const char *type, const char *line);
+ char **parse_list(const char *raw, unsigned int *count, const char sep, int skip_field);
+
++typedef int (*parse_line_t)(void *, const char *, uint);
++int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask,
++ char **buf0, size_t buf0len);
++
+ #endif
+--- a/libopkg/pkg_hash.c
++++ b/libopkg/pkg_hash.c
+@@ -23,6 +23,7 @@
+ #include "opkg_message.h"
+ #include "pkg_vec.h"
+ #include "pkg_hash.h"
++#include "parse_util.h"
+ #include "pkg_parse.h"
+ #include "opkg_utils.h"
+ #include "sprintf_alloc.h"
+@@ -119,8 +120,14 @@ pkg_hash_add_from_file(const char *file_
+ pkg->src = src;
+ pkg->dest = dest;
+
+- ret = pkg_parse_from_stream_nomalloc(pkg, fp, 0,
++ ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0,
+ &buf, len);
++
++ if (pkg->name == NULL) {
++ /* probably just a blank line */
++ ret = 1;
++ }
++
+ if (ret) {
+ pkg_deinit (pkg);
+ free(pkg);
+--- a/libopkg/pkg_parse.c
++++ b/libopkg/pkg_parse.c
+@@ -104,9 +104,11 @@ get_arch_priority(const char *arch)
+ return 0;
+ }
+
+-static int
+-pkg_parse_line(pkg_t *pkg, const char *line, uint mask)
++int
++pkg_parse_line(void *ptr, const char *line, uint mask)
+ {
++ pkg_t *pkg = (pkg_t *) ptr;
++
+ /* these flags are a bit hackish... */
+ static int reading_conffiles = 0, reading_description = 0;
+ int ret = 0;
+@@ -266,91 +268,6 @@ dont_reset_flags:
+ }
+
+ int
+-pkg_parse_from_stream_nomalloc(pkg_t *pkg, FILE *fp, uint mask,
+- char **buf0, size_t buf0len)
+-{
+- int ret, lineno;
+- char *buf, *nl;
+- size_t buflen;
+-
+- lineno = 1;
+- ret = 0;
+-
+- buflen = buf0len;
+- buf = *buf0;
+- buf[0] = '\0';
+-
+- while (1) {
+- if (fgets(buf, (int)buflen, fp) == NULL) {
+- if (ferror(fp)) {
+- opkg_perror(ERROR, "fgets");
+- ret = -1;
+- } else if (strlen(*buf0) == buf0len-1) {
+- opkg_msg(ERROR, "Missing new line character"
+- " at end of file!\n");
+- pkg_parse_line(pkg, *buf0, mask);
+- }
+- break;
+- }
+-
+- nl = strchr(buf, '\n');
+- if (nl == NULL) {
+- if (strlen(buf) < buflen-1) {
+- /*
+- * Line could be exactly buflen-1 long and
+- * missing a newline, but we won't know until
+- * fgets fails to read more data.
+- */
+- opkg_msg(ERROR, "Missing new line character"
+- " at end of file!\n");
+- pkg_parse_line(pkg, *buf0, mask);
+- break;
+- }
+- if (buf0len >= EXCESSIVE_LINE_LEN) {
+- opkg_msg(ERROR, "Excessively long line at "
+- "%d. Corrupt file?\n",
+- lineno);
+- ret = -1;
+- break;
+- }
+-
+- /*
+- * Realloc and point buf past the data already read,
+- * at the NULL terminator inserted by fgets.
+- * |<--------------- buf0len ----------------->|
+- * | |<------- buflen ---->|
+- * |---------------------|---------------------|
+- * buf0 buf
+- */
+- buflen = buf0len +1;
+- buf0len *= 2;
+- *buf0 = xrealloc(*buf0, buf0len);
+- buf = *buf0 + buflen -2;
+-
+- continue;
+- }
+-
+- *nl = '\0';
+-
+- lineno++;
+-
+- if (pkg_parse_line(pkg, *buf0, mask))
+- break;
+-
+- buf = *buf0;
+- buflen = buf0len;
+- buf[0] = '\0';
+- }
+-
+- if (pkg->name == NULL) {
+- /* probably just a blank line */
+- ret = 1;
+- }
+-
+- return ret;
+-}
+-
+-int
+ pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask)
+ {
+ int ret;
+@@ -358,8 +275,13 @@ pkg_parse_from_stream(pkg_t *pkg, FILE *
+ const size_t len = 4096;
+
+ buf = xmalloc(len);
+- ret = pkg_parse_from_stream_nomalloc(pkg, fp, mask, &buf, len);
++ ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len);
+ free(buf);
+
++ if (pkg->name == NULL) {
++ /* probably just a blank line */
++ ret = 1;
++ }
++
+ return ret;
+ }
+--- a/libopkg/pkg_parse.h
++++ b/libopkg/pkg_parse.h
+@@ -18,10 +18,11 @@
+ #ifndef PKG_PARSE_H
+ #define PKG_PARSE_H
+
++#include "pkg.h"
++
+ int parse_version(pkg_t *pkg, const char *raw);
+ int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask);
+-int pkg_parse_from_stream_nomalloc(pkg_t *pkg, FILE *fp, uint mask,
+- char **buf0, size_t buf0len);
++int pkg_parse_line(void *ptr, const char *line, uint mask);
+
+ #define EXCESSIVE_LINE_LEN (4096 << 8)
+
+--- a/libopkg/release_parse.c
++++ b/libopkg/release_parse.c
+@@ -23,8 +23,10 @@
+ #include "parse_util.h"
+
+ static int
+-release_parse_line(release_t *release, const char *line)
++release_parse_line(void *ptr, const char *line, uint mask)
+ {
++ release_t *release = (release_t *) ptr;
++
+ int ret = 0;
+ unsigned int count = 0;
+ char **list = 0;
+@@ -111,25 +113,14 @@ dont_reset_flags:
+ int
+ release_parse_from_stream(release_t *release, FILE *fp)
+ {
+- int ret = 0;
+- char *buf = NULL;
+- size_t buflen, nread;
+-
+- nread = getline(&buf, &buflen, fp);
+- while ( nread != -1 ) {
+- if (buf[nread-1] == '\n') buf[nread-1] = '\0';
+- if (release_parse_line(release, buf))
+- opkg_msg(DEBUG, "Failed to parse release line for %s:\n\t%s\n",
+- release->name, buf);
+- nread = getline(&buf, &buflen, fp);
+- }
+-
+- if (!feof(fp)) {
+- opkg_perror(ERROR, "Problems reading Release file for %sd\n", release->name);
+- ret = -1;
+- }
++ int ret;
++ char *buf;
++ const size_t len = 4096;
+
++ buf = xmalloc(len);
++ ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len);
+ free(buf);
++
+ return ret;
+ }
+
diff --git a/package/system/opkg/patches/030-fix-double-free.patch b/package/system/opkg/patches/030-fix-double-free.patch
new file mode 100644
index 0000000..312e06c
--- /dev/null
+++ b/package/system/opkg/patches/030-fix-double-free.patch
@@ -0,0 +1,10 @@
+--- a/libopkg/opkg_remove.c
++++ b/libopkg/opkg_remove.c
+@@ -138,7 +138,6 @@ opkg_remove_dependent_pkgs(pkg_t *pkg, a
+ for (i = 0; i < dependent_pkgs->len; i++) {
+ err = opkg_remove_pkg(dependent_pkgs->pkgs[i],0);
+ if (err) {
+- pkg_vec_free(dependent_pkgs);
+ break;
+ }
+ }
diff --git a/package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch b/package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch
new file mode 100644
index 0000000..9540668
--- /dev/null
+++ b/package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch
@@ -0,0 +1,31 @@
+--- a/libopkg/pkg_parse.c
++++ b/libopkg/pkg_parse.c
+@@ -20,6 +20,7 @@
+
+ #include <stdio.h>
+ #include <ctype.h>
++#include <unistd.h>
+
+ #include "pkg.h"
+ #include "opkg_utils.h"
+@@ -239,10 +240,16 @@ pkg_parse_line(void *ptr, const char *li
+
+ case ' ':
+ if ((mask & PFM_DESCRIPTION) && reading_description) {
+- pkg->description = xrealloc(pkg->description,
+- strlen(pkg->description)
+- + 1 + strlen(line) + 1);
+- strcat(pkg->description, "\n");
++ if (isatty(1)) {
++ pkg->description = xrealloc(pkg->description,
++ strlen(pkg->description)
++ + 1 + strlen(line) + 1);
++ strcat(pkg->description, "\n");
++ } else {
++ pkg->description = xrealloc(pkg->description,
++ strlen(pkg->description)
++ + 1 + strlen(line));
++ }
+ strcat(pkg->description, (line));
+ goto dont_reset_flags;
+ } else if ((mask & PFM_CONFFILES) && reading_conffiles) {
diff --git a/package/system/opkg/patches/050-add-case-insensitive-flag.patch b/package/system/opkg/patches/050-add-case-insensitive-flag.patch
new file mode 100644
index 0000000..4b9215b
--- /dev/null
+++ b/package/system/opkg/patches/050-add-case-insensitive-flag.patch
@@ -0,0 +1,169 @@
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -436,7 +436,7 @@ opkg_configure_packages(char *pkg_name)
+ for(i = 0; i < ordered->len; i++) {
+ pkg = ordered->pkgs[i];
+
+- if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++ if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ continue;
+
+ if (pkg->state_status == SS_UNPACKED) {
+@@ -610,7 +610,7 @@ opkg_list_cmd(int argc, char **argv)
+ for (i=0; i < available->len; i++) {
+ pkg = available->pkgs[i];
+ /* if we have package name or pattern and pkg does not match, then skip it */
+- if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++ if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ continue;
+ print_pkg(pkg);
+ }
+@@ -637,7 +637,7 @@ opkg_list_installed_cmd(int argc, char *
+ for (i=0; i < available->len; i++) {
+ pkg = available->pkgs[i];
+ /* if we have package name or pattern and pkg does not match, then skip it */
+- if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++ if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ continue;
+ print_pkg(pkg);
+ }
+@@ -666,7 +666,7 @@ opkg_list_changed_conffiles_cmd(int argc
+ for (i=0; i < available->len; i++) {
+ pkg = available->pkgs[i];
+ /* if we have package name or pattern and pkg does not match, then skip it */
+- if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++ if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ continue;
+ if (nv_pair_list_empty(&pkg->conffiles))
+ continue;
+@@ -722,7 +722,7 @@ opkg_info_status_cmd(int argc, char **ar
+
+ for (i=0; i < available->len; i++) {
+ pkg = available->pkgs[i];
+- if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
++ if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase)) {
+ continue;
+ }
+
+@@ -792,7 +792,7 @@ opkg_remove_cmd(int argc, char **argv)
+ for (i=0; i<argc; i++) {
+ for (a=0; a<available->len; a++) {
+ pkg = available->pkgs[a];
+- if (fnmatch(argv[i], pkg->name, 0)) {
++ if (fnmatch(argv[i], pkg->name, conf->nocase)) {
+ continue;
+ }
+ if (conf->restrict_to_default_dest) {
+@@ -926,7 +926,7 @@ opkg_depends_cmd(int argc, char **argv)
+ for (j=0; j<available_pkgs->len; j++) {
+ pkg = available_pkgs->pkgs[j];
+
+- if (fnmatch(argv[i], pkg->name, 0) != 0)
++ if (fnmatch(argv[i], pkg->name, conf->nocase) != 0)
+ continue;
+
+ depends_count = pkg->depends_count +
+@@ -1147,9 +1147,9 @@ opkg_what_provides_replaces_cmd(enum wha
+ ((what_field_type == WHATPROVIDES)
+ ? pkg->provides[k]
+ : pkg->replaces[k]);
+- if (fnmatch(target, apkg->name, 0) == 0) {
++ if (fnmatch(target, apkg->name, conf->nocase) == 0) {
+ opkg_msg(NOTICE, " %s", pkg->name);
+- if (strcmp(target, apkg->name) != 0)
++ if ((conf->nocase ? strcasecmp(target, apkg->name) : strcmp(target, apkg->name)) != 0)
+ opkg_msg(NOTICE, "\t%s %s\n",
+ rel_str, apkg->name);
+ opkg_message(NOTICE, "\n");
+@@ -1200,7 +1200,7 @@ opkg_search_cmd(int argc, char **argv)
+
+ for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
+ installed_file = (char *)iter->data;
+- if (fnmatch(argv[0], installed_file, 0)==0)
++ if (fnmatch(argv[0], installed_file, conf->nocase)==0)
+ print_pkg(pkg);
+ }
+
+--- a/libopkg/opkg_conf.c
++++ b/libopkg/opkg_conf.c
+@@ -62,6 +62,7 @@ opkg_option_t options[] = {
+ { "noaction", OPKG_OPT_TYPE_BOOL, &_conf.noaction },
+ { "download_only", OPKG_OPT_TYPE_BOOL, &_conf.download_only },
+ { "nodeps", OPKG_OPT_TYPE_BOOL, &_conf.nodeps },
++ { "nocase", OPKG_OPT_TYPE_BOOL, &_conf.nocase },
+ { "offline_root", OPKG_OPT_TYPE_STRING, &_conf.offline_root },
+ { "overlay_root", OPKG_OPT_TYPE_STRING, &_conf.overlay_root },
+ { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd },
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -24,6 +24,7 @@ extern opkg_conf_t *conf;
+ #include "config.h"
+
+ #include <stdarg.h>
++#include <fnmatch.h> /* FNM_CASEFOLD */
+
+ #include "hash_table.h"
+ #include "pkg_src_list.h"
+@@ -79,6 +80,7 @@ struct opkg_conf
+ int force_remove;
+ int check_signature;
+ int nodeps; /* do not follow dependencies */
++ int nocase; /* perform case insensitive matching */
+ char *offline_root;
+ char *overlay_root;
+ int query_all;
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -47,6 +47,7 @@ enum {
+ ARGS_OPT_NOACTION,
+ ARGS_OPT_DOWNLOAD_ONLY,
+ ARGS_OPT_NODEPS,
++ ARGS_OPT_NOCASE,
+ ARGS_OPT_AUTOREMOVE,
+ ARGS_OPT_CACHE,
+ };
+@@ -86,6 +87,7 @@ static struct option long_options[] = {
+ {"noaction", 0, 0, ARGS_OPT_NOACTION},
+ {"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ {"nodeps", 0, 0, ARGS_OPT_NODEPS},
++ {"nocase", 0, 0, ARGS_OPT_NOCASE},
+ {"offline", 1, 0, 'o'},
+ {"offline-root", 1, 0, 'o'},
+ {"add-arch", 1, 0, ARGS_OPT_ADD_ARCH},
+@@ -107,7 +109,7 @@ args_parse(int argc, char *argv[])
+ char *tuple, *targ;
+
+ while (1) {
+- c = getopt_long_only(argc, argv, "Ad:f:no:p:t:vV::",
++ c = getopt_long_only(argc, argv, "Ad:f:ino:p:t:vV::",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+@@ -122,6 +124,9 @@ args_parse(int argc, char *argv[])
+ case 'f':
+ conf->conf_file = xstrdup(optarg);
+ break;
++ case 'i':
++ conf->nocase = FNM_CASEFOLD;
++ break;
+ case 'o':
+ conf->offline_root = xstrdup(optarg);
+ break;
+@@ -176,6 +181,9 @@ args_parse(int argc, char *argv[])
+ case ARGS_OPT_NODEPS:
+ conf->nodeps = 1;
+ break;
++ case ARGS_OPT_NOCASE:
++ conf->nocase = FNM_CASEFOLD;
++ break;
+ case ARGS_OPT_ADD_ARCH:
+ case ARGS_OPT_ADD_DEST:
+ tuple = xstrdup(optarg);
+@@ -287,6 +295,7 @@ usage()
+ printf("\t--noaction No action -- test only\n");
+ printf("\t--download-only No action -- download only\n");
+ printf("\t--nodeps Do not follow dependencies\n");
++ printf("\t--nocase Perform case insensitive pattern matching\n");
+ printf("\t--force-removal-of-dependent-packages\n");
+ printf("\t Remove package and all dependencies\n");
+ printf("\t--autoremove Remove packages that were installed\n");
diff --git a/package/system/opkg/patches/060-add-find-command.patch b/package/system/opkg/patches/060-add-find-command.patch
new file mode 100644
index 0000000..1762534
--- /dev/null
+++ b/package/system/opkg/patches/060-add-find-command.patch
@@ -0,0 +1,58 @@
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -594,7 +594,7 @@ opkg_download_cmd(int argc, char **argv)
+
+
+ static int
+-opkg_list_cmd(int argc, char **argv)
++opkg_list_find_cmd(int argc, char **argv, int use_desc)
+ {
+ int i;
+ pkg_vec_t *available;
+@@ -610,7 +610,8 @@ opkg_list_cmd(int argc, char **argv)
+ for (i=0; i < available->len; i++) {
+ pkg = available->pkgs[i];
+ /* if we have package name or pattern and pkg does not match, then skip it */
+- if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
++ if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase) &&
++ (!use_desc || !pkg->description || fnmatch(pkg_name, pkg->description, conf->nocase)))
+ continue;
+ print_pkg(pkg);
+ }
+@@ -619,6 +620,18 @@ opkg_list_cmd(int argc, char **argv)
+ return 0;
+ }
+
++static int
++opkg_list_cmd(int argc, char **argv)
++{
++ return opkg_list_find_cmd(argc, argv, 0);
++}
++
++static int
++opkg_find_cmd(int argc, char **argv)
++{
++ return opkg_list_find_cmd(argc, argv, 1);
++}
++
+
+ static int
+ opkg_list_installed_cmd(int argc, char **argv)
+@@ -1262,6 +1275,7 @@ static opkg_cmd_t cmds[] = {
+ {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+ {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+ {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE},
++ {"find", 1, (opkg_cmd_fun_t)opkg_find_cmd, PFM_SOURCE},
+ {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+ {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+ {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -246,6 +246,7 @@ usage()
+ printf("\tlist-changed-conffiles List user modified configuration files\n");
+ printf("\tfiles <pkg> List files belonging to <pkg>\n");
+ printf("\tsearch <file|regexp> List package providing <file>\n");
++ printf("\tfind <regexp> List packages whose name or description matches <regexp>\n");
+ printf("\tinfo [pkg|regexp] Display all info for <pkg>\n");
+ printf("\tstatus [pkg|regexp] Display all status for <pkg>\n");
+ printf("\tdownload <pkg> Download <pkg> to current directory\n");
diff --git a/package/system/opkg/patches/070-use_gzipped_pkg_list.patch b/package/system/opkg/patches/070-use_gzipped_pkg_list.patch
new file mode 100644
index 0000000..d32b519
--- /dev/null
+++ b/package/system/opkg/patches/070-use_gzipped_pkg_list.patch
@@ -0,0 +1,120 @@
+--- a/libopkg/opkg.c
++++ b/libopkg/opkg.c
+@@ -592,49 +592,8 @@ opkg_update_package_lists(opkg_progress_
+ src->gzip ? "Packages.gz" : "Packages");
+
+ sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
+- if (src->gzip) {
+- FILE *in, *out;
+- struct _curl_cb_data cb_data;
+- char *tmp_file_name = NULL;
+
+- sprintf_alloc(&tmp_file_name, "%s/%s.gz", tmp,
+- src->name);
+-
+- opkg_msg(INFO, "Downloading %s to %s...\n", url,
+- tmp_file_name);
+-
+- cb_data.cb = progress_callback;
+- cb_data.progress_data = &pdata;
+- cb_data.user_data = user_data;
+- cb_data.start_range =
+- 100 * sources_done / sources_list_count;
+- cb_data.finish_range =
+- 100 * (sources_done + 1) / sources_list_count;
+-
+- err = opkg_download(url, tmp_file_name,
+- (curl_progress_func) curl_progress_cb,
+- &cb_data, 0);
+-
+- if (err == 0) {
+- opkg_msg(INFO, "Inflating %s...\n",
+- tmp_file_name);
+- in = fopen(tmp_file_name, "r");
+- out = fopen(list_file_name, "w");
+- if (in && out)
+- unzip(in, out);
+- else
+- err = 1;
+- if (in)
+- fclose(in);
+- if (out)
+- fclose(out);
+- unlink(tmp_file_name);
+- }
+- free(tmp_file_name);
+- } else
+- err = opkg_download(url, list_file_name, NULL, NULL, 0);
+-
+- if (err) {
++ if (opkg_download(url, list_file_name, NULL, NULL, 0)) {
+ opkg_msg(ERROR, "Couldn't retrieve %s\n", url);
+ result = -1;
+ }
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -162,30 +162,7 @@ opkg_update_cmd(int argc, char **argv)
+ sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
+
+ sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
+- if (src->gzip) {
+- char *tmp_file_name;
+- FILE *in, *out;
+-
+- sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
+- err = opkg_download(url, tmp_file_name, NULL, NULL, 0);
+- if (err == 0) {
+- opkg_msg(NOTICE, "Inflating %s.\n", url);
+- in = fopen (tmp_file_name, "r");
+- out = fopen (list_file_name, "w");
+- if (in && out)
+- unzip (in, out);
+- else
+- err = 1;
+- if (in)
+- fclose (in);
+- if (out)
+- fclose (out);
+- unlink (tmp_file_name);
+- }
+- free(tmp_file_name);
+- } else
+- err = opkg_download(url, list_file_name, NULL, NULL, 0);
+- if (err) {
++ if (opkg_download(url, list_file_name, NULL, NULL, 0)) {
+ failures++;
+ } else {
+ opkg_msg(NOTICE, "Updated list of available packages in %s.\n",
+--- a/libopkg/pkg_hash.c
++++ b/libopkg/pkg_hash.c
+@@ -102,12 +102,18 @@ pkg_hash_add_from_file(const char *file_
+ pkg_src_t *src, pkg_dest_t *dest, int is_status_file)
+ {
+ pkg_t *pkg;
+- FILE *fp;
++ FILE *fp, *fp_c = NULL;
+ char *buf;
+ const size_t len = 4096;
+ int ret = 0;
++ int pid;
+
+ fp = fopen(file_name, "r");
++ if (fp && src && src->gzip) {
++ fp_c = fp;
++ fp = gz_open(fp_c, &pid);
++ }
++
+ if (fp == NULL) {
+ opkg_perror(ERROR, "Failed to open %s", file_name);
+ return -1;
+@@ -154,6 +160,10 @@ pkg_hash_add_from_file(const char *file_
+
+ free(buf);
+ fclose(fp);
++ if (fp_c) {
++ fclose(fp_c);
++ gz_close(pid);
++ }
+
+ return ret;
+ }
diff --git a/package/system/opkg/patches/080-suppress-blank-package-fields.patch b/package/system/opkg/patches/080-suppress-blank-package-fields.patch
new file mode 100644
index 0000000..976b97d
--- /dev/null
+++ b/package/system/opkg/patches/080-suppress-blank-package-fields.patch
@@ -0,0 +1,16 @@
+--- a/libopkg/parse_util.c
++++ b/libopkg/parse_util.c
+@@ -35,7 +35,12 @@ is_field(const char *type, const char *l
+ char *
+ parse_simple(const char *type, const char *line)
+ {
+- return trim_xstrdup(line + strlen(type) + 1);
++ char *field = trim_xstrdup(line + strlen(type) + 1);
++ if (strlen(field) == 0) {
++ free(field);
++ return NULL;
++ }
++ return field;
+ }
+
+ /*
diff --git a/package/system/opkg/patches/090-suppress-blank-provides-field.patch b/package/system/opkg/patches/090-suppress-blank-provides-field.patch
new file mode 100644
index 0000000..7adf922
--- /dev/null
+++ b/package/system/opkg/patches/090-suppress-blank-provides-field.patch
@@ -0,0 +1,11 @@
+--- a/libopkg/pkg.c
++++ b/libopkg/pkg.c
+@@ -731,7 +731,7 @@ pkg_formatted_field(FILE *fp, pkg_t *pkg
+ } else if (strcasecmp(field, "Priority") == 0) {
+ fprintf(fp, "Priority: %s\n", pkg->priority);
+ } else if (strcasecmp(field, "Provides") == 0) {
+- if (pkg->provides_count) {
++ if (pkg->provides_count > 1) {
+ fprintf(fp, "Provides:");
+ for(i = 1; i < pkg->provides_count; i++) {
+ fprintf(fp, "%s %s", i == 1 ? "" : ",",
diff --git a/package/system/opkg/patches/100-add-force-checksum.patch b/package/system/opkg/patches/100-add-force-checksum.patch
new file mode 100644
index 0000000..5f65a75
--- /dev/null
+++ b/package/system/opkg/patches/100-add-force-checksum.patch
@@ -0,0 +1,85 @@
+--- a/libopkg/opkg_conf.c
++++ b/libopkg/opkg_conf.c
+@@ -54,6 +54,7 @@ opkg_option_t options[] = {
+ { "force_reinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_reinstall },
+ { "force_space", OPKG_OPT_TYPE_BOOL, &_conf.force_space },
+ { "force_postinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_postinstall },
++ { "force_checksum", OPKG_OPT_TYPE_BOOL, &_conf.force_checksum },
+ { "check_signature", OPKG_OPT_TYPE_BOOL, &_conf.check_signature },
+ { "ftp_proxy", OPKG_OPT_TYPE_STRING, &_conf.ftp_proxy },
+ { "http_proxy", OPKG_OPT_TYPE_STRING, &_conf.http_proxy },
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -78,6 +78,7 @@ struct opkg_conf
+ int force_removal_of_essential_packages;
+ int force_postinstall;
+ int force_remove;
++ int force_checksum;
+ int check_signature;
+ int nodeps; /* do not follow dependencies */
+ int nocase; /* perform case insensitive matching */
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1327,12 +1327,19 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+ file_md5 = file_md5sum_alloc(pkg->local_filename);
+ if (file_md5 && strcmp(file_md5, pkg->md5sum))
+ {
+- opkg_msg(ERROR, "Package %s md5sum mismatch. "
+- "Either the opkg or the package index are corrupt. "
+- "Try 'opkg update'.\n",
+- pkg->name);
+- free(file_md5);
+- return -1;
++ if (!conf->force_checksum)
++ {
++ opkg_msg(ERROR, "Package %s md5sum mismatch. "
++ "Either the opkg or the package index are corrupt. "
++ "Try 'opkg update'.\n",
++ pkg->name);
++ free(file_md5);
++ return -1;
++ }
++ else
++ {
++ opkg_msg(NOTICE, "Ignored %s md5sum mismatch.\n", pkg->name);
++ }
+ }
+ if (file_md5)
+ free(file_md5);
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -42,6 +42,7 @@ enum {
+ ARGS_OPT_FORCE_SPACE,
+ ARGS_OPT_FORCE_POSTINSTALL,
+ ARGS_OPT_FORCE_REMOVE,
++ ARGS_OPT_FORCE_CHECKSUM,
+ ARGS_OPT_ADD_ARCH,
+ ARGS_OPT_ADD_DEST,
+ ARGS_OPT_NOACTION,
+@@ -84,6 +85,8 @@ static struct option long_options[] = {
+ {"force_postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL},
+ {"force-remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ {"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
++ {"force-checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
++ {"force_checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
+ {"noaction", 0, 0, ARGS_OPT_NOACTION},
+ {"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ {"nodeps", 0, 0, ARGS_OPT_NODEPS},
+@@ -178,6 +181,9 @@ args_parse(int argc, char *argv[])
+ case ARGS_OPT_FORCE_REMOVE:
+ conf->force_remove = 1;
+ break;
++ case ARGS_OPT_FORCE_CHECKSUM:
++ conf->force_checksum = 1;
++ break;
+ case ARGS_OPT_NODEPS:
+ conf->nodeps = 1;
+ break;
+@@ -293,6 +299,7 @@ usage()
+ printf("\t--force-space Disable free space checks\n");
+ printf("\t--force-postinstall Run postinstall scripts even in offline mode\n");
+ printf("\t--force-remove Remove package even if prerm script fails\n");
++ printf("\t--force-checksum Don't fail on checksum mismatches\n");
+ printf("\t--noaction No action -- test only\n");
+ printf("\t--download-only No action -- download only\n");
+ printf("\t--nodeps Do not follow dependencies\n");
diff --git a/package/system/opkg/patches/110-upgrade.patch b/package/system/opkg/patches/110-upgrade.patch
new file mode 100644
index 0000000..071df0e
--- /dev/null
+++ b/package/system/opkg/patches/110-upgrade.patch
@@ -0,0 +1,49 @@
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1405,9 +1405,10 @@
+ opkg_state_changed++;
+ pkg->state_flag |= SF_FILELIST_CHANGED;
+
+- if (old_pkg)
++ if (old_pkg) {
+ pkg_remove_orphan_dependent(pkg, old_pkg);
+-
++ pkg->is_upgrade = 1;
++ }
+ /* XXX: BUG: we really should treat replacement more like an upgrade
+ * Instead, we're going to remove the replacees
+ */
+@@ -1466,7 +1467,7 @@
+ }
+
+
+- opkg_msg(INFO, "Installing maintainer scripts.\n");
++ opkg_msg(INFO, "%s maintainer scripts.\n", (pkg->is_upgrade) ? ("Upgrading") : ("Installing"));
+ if (install_maintainer_scripts(pkg, old_pkg)) {
+ opkg_msg(ERROR, "Failed to extract maintainer scripts for %s."
+ " Package debris may remain!\n",
+--- a/libopkg/pkg.c
++++ b/libopkg/pkg.c
+@@ -1285,6 +1285,12 @@
+ setenv("PKG_ROOT",
+ pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
+
++ if (pkg->is_upgrade)
++ setenv("PKG_UPGRADE", "1", 1);
++ else
++ setenv("PKG_UPGRADE", "0", 1);
++
++
+ if (! file_exists(path)) {
+ free(path);
+ return 0;
+--- a/libopkg/pkg.h
++++ b/libopkg/pkg.h
+@@ -184,6 +184,7 @@
+ /* this flag specifies whether the package was installed to satisfy another
+ * package's dependancies */
+ int auto_installed;
++ int is_upgrade;
+ };
+
+ pkg_t *pkg_new(void);
diff --git a/package/system/opkg/patches/200-usign_support.patch b/package/system/opkg/patches/200-usign_support.patch
new file mode 100644
index 0000000..991708a
--- /dev/null
+++ b/package/system/opkg/patches/200-usign_support.patch
@@ -0,0 +1,91 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -169,6 +169,15 @@ if test "x$want_gpgme" = "xyes"; then
+ fi
+ fi
+
++AC_ARG_ENABLE(usign,
++ AC_HELP_STRING([--enable-usign], [Enable signature checking with usign
++ [[default=yes]] ]),
++ [want_usign="$enableval"], [want_usign="yes"])
++
++if test "x$want_usign" = "xyes"; then
++ AC_DEFINE(HAVE_USIGN, 1, [Define if you want usign support])
++fi
++
+ AC_SUBST(GPGME_CFLAGS)
+ AC_SUBST(GPGME_LIBS)
+
+--- a/libopkg/opkg.c
++++ b/libopkg/opkg.c
+@@ -599,7 +599,7 @@ opkg_update_package_lists(opkg_progress_
+ }
+ free(url);
+
+-#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
++#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
+ if (conf->check_signature) {
+ char *sig_file_name;
+ /* download detached signitures to verify the package lists */
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -169,7 +169,7 @@ opkg_update_cmd(int argc, char **argv)
+ list_file_name);
+ }
+ free(url);
+-#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
++#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
+ if (conf->check_signature) {
+ /* download detached signitures to verify the package lists */
+ /* get the url for the sig file */
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1288,7 +1288,7 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+ }
+
+ /* check that the repository is valid */
+- #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
++ #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
+ char *list_file_name, *sig_file_name, *lists_dir;
+
+ /* check to ensure the package has come from a repository */
+--- a/libopkg/opkg_download.c
++++ b/libopkg/opkg_download.c
+@@ -19,6 +19,7 @@
+
+ #include "config.h"
+
++#include <sys/wait.h>
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <libgen.h>
+@@ -342,7 +343,28 @@ opkg_prepare_url_for_install(const char
+ int
+ opkg_verify_file (char *text_file, char *sig_file)
+ {
+-#if defined HAVE_GPGME
++#if defined HAVE_USIGN
++ int status = -1;
++ int pid;
++
++ if (conf->check_signature == 0 )
++ return 0;
++
++ pid = fork();
++ if (pid < 0)
++ return -1;
++
++ if (!pid) {
++ execl("/usr/sbin/opkg-key", "opkg-key", "verify", sig_file, text_file, NULL);
++ exit(255);
++ }
++
++ waitpid(pid, &status, 0);
++ if (!WIFEXITED(status) || WEXITSTATUS(status))
++ return -1;
++
++ return 0;
++#elif defined HAVE_GPGME
+ if (conf->check_signature == 0 )
+ return 0;
+ int status = -1;
diff --git a/package/system/opkg/patches/210-add-force-signature.patch b/package/system/opkg/patches/210-add-force-signature.patch
new file mode 100644
index 0000000..c41eab0
--- /dev/null
+++ b/package/system/opkg/patches/210-add-force-signature.patch
@@ -0,0 +1,70 @@
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -80,6 +80,7 @@ struct opkg_conf
+ int force_remove;
+ int force_checksum;
+ int check_signature;
++ int force_signature;
+ int nodeps; /* do not follow dependencies */
+ int nocase; /* perform case insensitive matching */
+ char *offline_root;
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -51,6 +51,7 @@ enum {
+ ARGS_OPT_NOCASE,
+ ARGS_OPT_AUTOREMOVE,
+ ARGS_OPT_CACHE,
++ ARGS_OPT_FORCE_SIGNATURE,
+ };
+
+ static struct option long_options[] = {
+@@ -87,6 +88,8 @@ static struct option long_options[] = {
+ {"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ {"force-checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
+ {"force_checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
++ {"force-signature", 0, 0, ARGS_OPT_FORCE_SIGNATURE},
++ {"force_signature", 0, 0, ARGS_OPT_FORCE_SIGNATURE},
+ {"noaction", 0, 0, ARGS_OPT_NOACTION},
+ {"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ {"nodeps", 0, 0, ARGS_OPT_NODEPS},
+@@ -210,6 +213,9 @@ args_parse(int argc, char *argv[])
+ case ARGS_OPT_DOWNLOAD_ONLY:
+ conf->download_only = 1;
+ break;
++ case ARGS_OPT_FORCE_SIGNATURE:
++ conf->force_signature = 1;
++ break;
+ case ':':
+ parse_err = -1;
+ break;
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1306,13 +1306,15 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+ if (opkg_verify_file (list_file_name, sig_file_name)){
+ opkg_msg(ERROR, "Failed to verify the signature of %s.\n",
+ list_file_name);
+- return -1;
++ if (!conf->force_signature)
++ return -1;
+ }
+ }else{
+ opkg_msg(ERROR, "Signature file is missing for %s. "
+ "Perhaps you need to run 'opkg update'?\n",
+ pkg->name);
+- return -1;
++ if (!conf->force_signature)
++ return -1;
+ }
+
+ free (lists_dir);
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -196,7 +196,7 @@ opkg_update_cmd(int argc, char **argv)
+ else
+ opkg_msg(NOTICE, "Signature check failed.\n");
+ }
+- if (err) {
++ if (err && !conf->force_signature) {
+ /* The signature was wrong so delete it */
+ opkg_msg(NOTICE, "Remove wrong Signature file.\n");
+ unlink (tmp_file_name);
diff --git a/package/system/opkg/patches/220-drop-release-support.patch b/package/system/opkg/patches/220-drop-release-support.patch
new file mode 100644
index 0000000..41f271f
--- /dev/null
+++ b/package/system/opkg/patches/220-drop-release-support.patch
@@ -0,0 +1,812 @@
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -15,7 +15,6 @@
+ opkg_upgrade.c opkg_upgrade.h \
+ opkg_remove.c opkg_remove.h
+ opkg_db_sources = opkg_conf.c opkg_conf.h \
+- release.c release.h release_parse.c release_parse.h \
+ opkg_utils.c opkg_utils.h pkg.c pkg.h hash_table.h \
+ pkg_depends.c pkg_depends.h pkg_extract.c pkg_extract.h \
+ hash_table.c pkg_hash.c pkg_hash.h pkg_parse.c pkg_parse.h \
+@@ -28,7 +27,6 @@
+ active_list.c active_list.h list.h
+ opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \
+ parse_util.c parse_util.h \
+- cksum_list.c cksum_list.h \
+ sprintf_alloc.c sprintf_alloc.h \
+ xregex.c xregex.h xsystem.c xsystem.h
+ if HAVE_PATHFINDER
+--- a/libopkg/cksum_list.c
++++ /dev/null
+@@ -1,87 +0,0 @@
+-/* cksum_lis.c - the opkg package management system
+-
+- Copyright (C) 2010,2011 Javier Palacios
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-*/
+-
+-#include "config.h"
+-
+-#include <stdio.h>
+-
+-#include "cksum_list.h"
+-#include "libbb/libbb.h"
+-
+-
+-int cksum_init(cksum_t *cksum, char **itemlist)
+-{
+- cksum->value = xstrdup(*itemlist++);
+- cksum->size = atoi(*itemlist++);
+- cksum->name = xstrdup(*itemlist++);
+-
+- return 0;
+-}
+-
+-void cksum_deinit(cksum_t *cksum)
+-{
+- free (cksum->name);
+- cksum->name = NULL;
+-
+- free (cksum->value);
+- cksum->value = NULL;
+-}
+-
+-void cksum_list_init(cksum_list_t *list)
+-{
+- void_list_init((void_list_t *) list);
+-}
+-
+-void cksum_list_deinit(cksum_list_t *list)
+-{
+- cksum_list_elt_t *iter, *n;
+- cksum_t *cksum;
+-
+- list_for_each_entry_safe(iter, n, &list->head, node) {
+- cksum = (cksum_t *)iter->data;
+- cksum_deinit(cksum);
+-
+- /* malloced in cksum_list_append */
+- free(cksum);
+- iter->data = NULL;
+- }
+- void_list_deinit((void_list_t *) list);
+-}
+-
+-cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist)
+-{
+- /* freed in cksum_list_deinit */
+- cksum_t *cksum = xcalloc(1, sizeof(cksum_t));
+- cksum_init(cksum, itemlist);
+-
+- void_list_append((void_list_t *) list, cksum);
+-
+- return cksum;
+-}
+-
+-const cksum_t *cksum_list_find(cksum_list_t *list, const char *name)
+-{
+- cksum_list_elt_t *iter;
+- cksum_t *cksum;
+-
+- list_for_each_entry(iter, &list->head, node) {
+- cksum = (cksum_t *)iter->data;
+- if (strcmp(cksum->name, name) == 0) {
+- return cksum;
+- }
+- }
+- return NULL;
+-}
+-
+--- a/libopkg/cksum_list.h
++++ /dev/null
+@@ -1,46 +0,0 @@
+-/* cksum_list.h - the opkg package management system
+-
+- Copyright (C) 2010,2011 Javier Palacios
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-*/
+-
+-#ifndef CKSUM_LIST_H
+-#define CKSUM_LIST_H
+-
+-typedef struct
+-{
+- char *name;
+- char *value;
+- int size;
+-} cksum_t;
+-
+-int cksum_init(cksum_t *cksum, char **itemlist);
+-void cksum_deinit(cksum_t *cksum);
+-
+-#include "void_list.h"
+-
+-typedef struct void_list_elt cksum_list_elt_t;
+-
+-typedef struct void_list cksum_list_t;
+-
+-static inline int cksum_list_empty(cksum_list_t *list)
+-{
+- return void_list_empty ((void_list_t *)list);
+-}
+-
+-void cksum_list_init(cksum_list_t *list);
+-void cksum_list_deinit(cksum_list_t *list);
+-
+-cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist);
+-const cksum_t *cksum_list_find(cksum_list_t *list, const char *name);
+-
+-#endif
+--- a/libopkg/release.c
++++ /dev/null
+@@ -1,342 +0,0 @@
+-/* release.c - the opkg package management system
+-
+- Copyright (C) 2010,2011 Javier Palacios
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-*/
+-
+-#include <unistd.h>
+-#include <ctype.h>
+-
+-#include "release.h"
+-#include "opkg_utils.h"
+-#include "libbb/libbb.h"
+-
+-#include "opkg_download.h"
+-#include "sprintf_alloc.h"
+-
+-#include "release_parse.h"
+-
+-#include "parse_util.h"
+-#include "file_util.h"
+-
+-static void
+-release_init(release_t *release)
+-{
+- release->name = NULL;
+- release->datestring = NULL;
+- release->architectures = NULL;
+- release->architectures_count = 0;
+- release->components = NULL;
+- release->components_count = 0;
+- release->complist = NULL;
+- release->complist_count = 0;
+-}
+-
+-release_t *
+-release_new(void)
+-{
+- release_t *release;
+-
+- release = xcalloc(1, sizeof(release_t));
+- release_init(release);
+-
+- return release;
+-}
+-
+-void
+-release_deinit(release_t *release)
+-{
+- int i;
+-
+- free(release->name);
+- free(release->datestring);
+-
+- for(i = 0; i < release->architectures_count; i++){
+- free(release->architectures[i]);
+- }
+- free(release->architectures);
+-
+- for(i = 0; i < release->components_count; i++){
+- free(release->components[i]);
+- }
+- free(release->components);
+-
+- for(i = 0; i < release->complist_count; i++){
+- free(release->complist[i]);
+- }
+- free(release->complist);
+-
+-}
+-
+-int
+-release_init_from_file(release_t *release, const char *filename)
+-{
+- int err = 0;
+- FILE *release_file;
+-
+- release_file = fopen(filename, "r");
+- if (release_file == NULL) {
+- opkg_perror(ERROR, "Failed to open %s", filename);
+- return -1;
+- }
+-
+- err=release_parse_from_stream(release, release_file);
+- if (!err) {
+- if (!release_arch_supported(release)) {
+- opkg_msg(ERROR, "No valid architecture found on Release file.\n");
+- err = -1;
+- }
+- }
+-
+- return err;
+-}
+-
+-const char *
+-item_in_list(const char *comp, char **complist, const unsigned int count)
+-{
+- int i;
+-
+- if (!complist)
+- return comp;
+-
+- for(i = 0; i < count; i++){
+- if (strcmp(comp, complist[i]) == 0)
+- return complist[i];
+- }
+-
+- return NULL;
+-}
+-
+-int
+-release_arch_supported(release_t *release)
+-{
+- nv_pair_list_elt_t *l;
+-
+- list_for_each_entry(l , &conf->arch_list.head, node) {
+- nv_pair_t *nv = (nv_pair_t *)l->data;
+- if (item_in_list(nv->name, release->architectures, release->architectures_count)) {
+- opkg_msg(DEBUG, "Arch %s (priority %s) supported for dist %s.\n",
+- nv->name, nv->value, release->name);
+- return 1;
+- }
+- }
+-
+- return 0;
+-}
+-
+-int
+-release_comps_supported(release_t *release, const char *complist)
+-{
+- int ret = 1;
+- int i;
+-
+- if (complist) {
+- release->complist = parse_list(complist, &release->complist_count, ' ', 1);
+- for(i = 0; i < release->complist_count; i++){
+- if (!item_in_list(release->complist[i], release->components, release->components_count)) {
+- opkg_msg(ERROR, "Component %s not supported for dist %s.\n",
+- release->complist[i], release->name);
+- ret = 0;
+- }
+- }
+- }
+-
+- return ret;
+-}
+-
+-const char **
+-release_comps(release_t *release, unsigned int *count)
+-{
+- char **comps = release->complist;
+-
+- if (!comps) {
+- comps = release->components;
+- *count = release->components_count;
+- } else {
+- *count = release->complist_count;
+- }
+-
+- return (const char **)comps;
+-}
+-
+-int
+-release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir)
+-{
+- int ret = 0;
+- unsigned int ncomp;
+- const char **comps = release_comps(release, &ncomp);
+- nv_pair_list_elt_t *l;
+- int i;
+-
+- for(i = 0; i < ncomp; i++){
+- int err = 0;
+- char *prefix;
+-
+- sprintf_alloc(&prefix, "%s/dists/%s/%s/binary", dist->value, dist->name,
+- comps[i]);
+-
+- list_for_each_entry(l , &conf->arch_list.head, node) {
+- char *url;
+- char *tmp_file_name, *list_file_name;
+- char *subpath = NULL;
+-
+- nv_pair_t *nv = (nv_pair_t *)l->data;
+-
+- sprintf_alloc(&list_file_name, "%s/%s-%s-%s", lists_dir, dist->name, comps[i], nv->name);
+-
+- sprintf_alloc(&tmp_file_name, "%s/%s-%s-%s%s", tmpdir, dist->name, comps[i], nv->name, ".gz");
+-
+- sprintf_alloc(&subpath, "%s/binary-%s/%s", comps[i], nv->name, dist->gzip ? "Packages.gz" : "Packages");
+-
+- if (dist->gzip) {
+- sprintf_alloc(&url, "%s-%s/Packages.gz", prefix, nv->name);
+- err = opkg_download(url, tmp_file_name, NULL, NULL, 1);
+- if (!err) {
+- err = release_verify_file(release, tmp_file_name, subpath);
+- if (err) {
+- unlink (tmp_file_name);
+- unlink (list_file_name);
+- }
+- }
+- if (!err) {
+- FILE *in, *out;
+- opkg_msg(NOTICE, "Inflating %s.\n", url);
+- in = fopen (tmp_file_name, "r");
+- out = fopen (list_file_name, "w");
+- if (in && out) {
+- err = unzip (in, out);
+- if (err)
+- opkg_msg(INFO, "Corrumpt file at %s.\n", url);
+- } else
+- err = 1;
+- if (in)
+- fclose (in);
+- if (out)
+- fclose (out);
+- unlink (tmp_file_name);
+- }
+- free(url);
+- }
+-
+- if (err) {
+- sprintf_alloc(&url, "%s-%s/Packages", prefix, nv->name);
+- err = opkg_download(url, list_file_name, NULL, NULL, 1);
+- if (!err) {
+- err = release_verify_file(release, tmp_file_name, subpath);
+- if (err)
+- unlink (list_file_name);
+- }
+- free(url);
+- }
+-
+- free(tmp_file_name);
+- free(list_file_name);
+- }
+-
+- if(err)
+- ret = 1;
+-
+- free(prefix);
+- }
+-
+- return ret;
+-}
+-
+-int
+-release_get_size(release_t *release, const char *pathname)
+-{
+- const cksum_t *cksum;
+-
+- if (release->md5sums) {
+- cksum = cksum_list_find(release->md5sums, pathname);
+- return cksum->size;
+- }
+-
+-#ifdef HAVE_SHA256
+- if (release->sha256sums) {
+- cksum = cksum_list_find(release->sha256sums, pathname);
+- return cksum->size;
+- }
+-#endif
+-
+- return -1;
+-}
+-
+-const char *
+-release_get_md5(release_t *release, const char *pathname)
+-{
+- const cksum_t *cksum;
+-
+- if (release->md5sums) {
+- cksum = cksum_list_find(release->md5sums, pathname);
+- return cksum->value;
+- }
+-
+- return '\0';
+-}
+-
+-#ifdef HAVE_SHA256
+-const char *
+-release_get_sha256(release_t *release, const char *pathname)
+-{
+- const cksum_t *cksum;
+-
+- if (release->sha256sums) {
+- cksum = cksum_list_find(release->sha256sums, pathname);
+- return cksum->value;
+- }
+-
+- return '\0';
+-}
+-#endif
+-
+-int
+-release_verify_file(release_t *release, const char* file_name, const char *pathname)
+-{
+- struct stat f_info;
+- char *f_md5 = NULL;
+- const char *md5 = release_get_md5(release, pathname);
+-#ifdef HAVE_SHA256
+- char *f_sha256 = NULL;
+- const char *sha256 = release_get_sha256(release, pathname);
+-#endif
+- int ret = 0;
+-
+- if (stat(file_name, &f_info) || (f_info.st_size!=release_get_size(release, pathname))) {
+- opkg_msg(ERROR, "Size verification failed for %s - %s.\n", release->name, pathname);
+- ret = 1;
+- } else {
+-
+- f_md5 = file_md5sum_alloc(file_name);
+-#ifdef HAVE_SHA256
+- f_sha256 = file_sha256sum_alloc(file_name);
+-#endif
+-
+- if (md5 && strcmp(md5, f_md5)) {
+- opkg_msg(ERROR, "MD5 verification failed for %s - %s.\n", release->name, pathname);
+- ret = 1;
+-#ifdef HAVE_SHA256
+- } else if (sha256 && strcmp(sha256, f_sha256)) {
+- opkg_msg(ERROR, "SHA256 verification failed for %s - %s.\n", release->name, pathname);
+- ret = 1;
+-#endif
+- }
+-
+- }
+-
+- free(f_md5);
+-#ifdef HAVE_SHA256
+- free(f_sha256);
+-#endif
+-
+- return ret;
+-}
+--- a/libopkg/release.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/* release.h - the opkg package management system
+-
+- Copyright (C) 2010,2011 Javier Palacios
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-*/
+-
+-#ifndef RELEASE_H
+-#define RELEASE_H
+-
+-#include <stdio.h>
+-#include "pkg.h"
+-#include "cksum_list.h"
+-
+-struct release
+-{
+- char *name;
+- char *datestring;
+- char **architectures;
+- unsigned int architectures_count;
+- char **components;
+- unsigned int components_count;
+- cksum_list_t *md5sums;
+-#ifdef HAVE_SHA256
+- cksum_list_t *sha256sums;
+-#endif
+- char **complist;
+- unsigned int complist_count;
+-};
+-
+-typedef struct release release_t;
+-
+-release_t *release_new(void);
+-void release_deinit(release_t *release);
+-int release_init_from_file(release_t *release, const char *filename);
+-
+-int release_arch_supported(release_t *release);
+-int release_comps_supported(release_t *release, const char *complist);
+-int release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir);
+-
+-const char **release_comps(release_t *release, unsigned int *count);
+-
+-int release_verify_file(release_t *release, const char *filename, const char *pathname);
+-
+-#endif
+--- a/libopkg/release_parse.c
++++ /dev/null
+@@ -1,126 +0,0 @@
+-/* release_parse.c - the opkg package management system
+-
+- Copyright (C) 2010,2011 Javier Palacios
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-*/
+-
+-#include "config.h"
+-
+-#include <stdio.h>
+-
+-#include "release.h"
+-#include "release_parse.h"
+-#include "libbb/libbb.h"
+-#include "parse_util.h"
+-
+-static int
+-release_parse_line(void *ptr, const char *line, uint mask)
+-{
+- release_t *release = (release_t *) ptr;
+-
+- int ret = 0;
+- unsigned int count = 0;
+- char **list = 0;
+- static int reading_md5sums = 0;
+-#ifdef HAVE_SHA256
+- static int reading_sha256sums = 0;
+-#endif
+-
+- switch (*line) {
+- case 'A':
+- if (is_field("Architectures", line)) {
+- release->architectures = parse_list(line, &release->architectures_count, ' ', 0);
+- }
+- break;
+-
+- case 'C':
+- if (is_field("Codename", line)) {
+- release->name = parse_simple("Codename", line);
+- }
+- else if (is_field("Components", line)) {
+- release->components = parse_list(line, &release->components_count, ' ', 0);
+- }
+- break;
+-
+- case 'D':
+- if (is_field("Date", line)) {
+- release->datestring = parse_simple("Date", line);
+- }
+- break;
+-
+- case 'M':
+- if (is_field("MD5sum", line)) {
+- reading_md5sums = 1;
+- if (release->md5sums == NULL) {
+- release->md5sums = xcalloc(1, sizeof(cksum_list_t));
+- cksum_list_init(release->md5sums);
+- }
+- goto dont_reset_flags;
+- }
+- break;
+-
+-#ifdef HAVE_SHA256
+- case 'S':
+- if (is_field("SHA256", line)) {
+- reading_sha256sums = 1;
+- if (release->sha256sums == NULL) {
+- release->sha256sums = xcalloc(1, sizeof(cksum_list_t));
+- cksum_list_init(release->sha256sums);
+- }
+- goto dont_reset_flags;
+- }
+- break;
+-#endif
+-
+- case ' ':
+- if (reading_md5sums) {
+- list = parse_list(line, &count, ' ', 1);
+- cksum_list_append(release->md5sums, list);
+- goto dont_reset_flags;
+- }
+-#ifdef HAVE_SHA256
+- else if (reading_sha256sums) {
+- list = parse_list(line, &count, ' ', 1);
+- cksum_list_append(release->sha256sums, list);
+- goto dont_reset_flags;
+- }
+-#endif
+- break;
+-
+- default:
+- ret = 1;
+- }
+-
+- reading_md5sums = 0;
+-#ifdef HAVE_SHA256
+- reading_sha256sums = 0;
+-#endif
+-
+-dont_reset_flags:
+-
+- return ret;
+-}
+-
+-int
+-release_parse_from_stream(release_t *release, FILE *fp)
+-{
+- int ret;
+- char *buf;
+- const size_t len = 4096;
+-
+- buf = xmalloc(len);
+- ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len);
+- free(buf);
+-
+- return ret;
+-}
+-
+--- a/libopkg/release_parse.h
++++ /dev/null
+@@ -1,21 +0,0 @@
+-/* release_parse.h - the opkg package management system
+-
+- Copyright (C) 2010,2011 Javier Palacios
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-*/
+-
+-#ifndef RELEASE_PARSE_H
+-#define RELEASE_PARSE_H
+-
+-int release_parse_from_stream(release_t *release, FILE *fp);
+-
+-#endif
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -27,7 +27,6 @@
+ #include "opkg_conf.h"
+ #include "opkg_cmd.h"
+ #include "opkg_message.h"
+-#include "release.h"
+ #include "pkg.h"
+ #include "pkg_dest.h"
+ #include "pkg_parse.h"
+@@ -114,39 +113,6 @@
+ }
+
+
+- for (iter = void_list_first(&conf->dist_src_list); iter; iter = void_list_next(&conf->dist_src_list, iter)) {
+- char *url, *list_file_name;
+-
+- src = (pkg_src_t *)iter->data;
+-
+- sprintf_alloc(&url, "%s/dists/%s/Release", src->value, src->name);
+-
+- sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
+- err = opkg_download(url, list_file_name, NULL, NULL, 0);
+- if (!err) {
+- opkg_msg(NOTICE, "Downloaded release files for dist %s.\n",
+- src->name);
+- release_t *release = release_new();
+- err = release_init_from_file(release, list_file_name);
+- if (!err) {
+- if (!release_comps_supported(release, src->extra_data))
+- err = -1;
+- }
+- if (!err) {
+- err = release_download(release, src, lists_dir, tmp);
+- }
+- release_deinit(release);
+- if (err)
+- unlink(list_file_name);
+- }
+-
+- if (err)
+- failures++;
+-
+- free(list_file_name);
+- free(url);
+- }
+-
+ for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
+ char *url, *list_file_name;
+
+--- a/libopkg/pkg_hash.c
++++ b/libopkg/pkg_hash.c
+@@ -18,7 +18,6 @@
+ #include <stdio.h>
+
+ #include "hash_table.h"
+-#include "release.h"
+ #include "pkg.h"
+ #include "opkg_message.h"
+ #include "pkg_vec.h"
+@@ -183,40 +182,6 @@
+ lists_dir = conf->restrict_to_default_dest ?
+ conf->default_dest->lists_dir : conf->lists_dir;
+
+- for (iter = void_list_first(&conf->dist_src_list); iter;
+- iter = void_list_next(&conf->dist_src_list, iter)) {
+-
+- src = (pkg_src_t *)iter->data;
+-
+- sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name);
+-
+- if (file_exists(list_file)) {
+- int i;
+- release_t *release = release_new();
+- if(release_init_from_file(release, list_file)) {
+- free(list_file);
+- return -1;
+- }
+-
+- unsigned int ncomp;
+- const char **comps = release_comps(release, &ncomp);
+- subdist = (pkg_src_t *) xmalloc(sizeof(pkg_src_t));
+- memcpy(subdist, src, sizeof(pkg_src_t));
+-
+- for(i = 0; i < ncomp; i++){
+- subdist->name = NULL;
+- sprintf_alloc(&subdist->name, "%s-%s", src->name, comps[i]);
+- if (dist_hash_add_from_file(lists_dir, subdist)) {
+- free(subdist->name); free(subdist);
+- free(list_file);
+- return -1;
+- }
+- }
+- free(subdist->name); free(subdist);
+- }
+- free(list_file);
+- }
+-
+ for (iter = void_list_first(&conf->pkg_src_list); iter;
+ iter = void_list_next(&conf->pkg_src_list, iter)) {
+
diff --git a/package/system/opkg/patches/230-drop_md5_support.patch b/package/system/opkg/patches/230-drop_md5_support.patch
new file mode 100644
index 0000000..63671e5
--- /dev/null
+++ b/package/system/opkg/patches/230-drop_md5_support.patch
@@ -0,0 +1,161 @@
+--- a/libopkg/conffile.c
++++ b/libopkg/conffile.c
+@@ -36,7 +36,7 @@
+
+ int conffile_has_been_modified(conffile_t *conffile)
+ {
+- char *md5sum;
++ char *chksum;
+ char *filename = conffile->name;
+ char *root_filename;
+ int ret = 1;
+@@ -48,16 +48,19 @@
+
+ root_filename = root_filename_alloc(filename);
+
+- md5sum = file_md5sum_alloc(root_filename);
+-
+- if (md5sum && (ret = strcmp(md5sum, conffile->value))) {
+- opkg_msg(INFO, "Conffile %s:\n\told md5=%s\n\tnew md5=%s\n",
+- conffile->name, md5sum, conffile->value);
++#ifdef HAVE_MD5
++ chksum = file_md5sum_alloc(root_filename);
++#else
++ chksum = file_sha256sum_alloc(root_filename);
++#endif
++ if (chksum && (ret = strcmp(chksum, conffile->value))) {
++ opkg_msg(INFO, "Conffile %s:\n\told chk=%s\n\tnew chk=%s\n",
++ conffile->name, chksum, conffile->value);
+ }
+
+ free(root_filename);
+- if (md5sum)
+- free(md5sum);
++ if (chksum)
++ free(chksum);
+
+ return ret;
+ }
+--- a/libopkg/file_util.c
++++ b/libopkg/file_util.c
+@@ -26,7 +26,9 @@
+
+ #include "sprintf_alloc.h"
+ #include "file_util.h"
++#ifdef HAVE_MD5
+ #include "md5.h"
++#endif
+ #include "libbb/libbb.h"
+
+ #if defined HAVE_SHA256
+@@ -135,6 +137,7 @@
+ return make_directory(path, mode, FILEUTILS_RECUR);
+ }
+
++#ifdef HAVE_MD5
+ char *file_md5sum_alloc(const char *file_name)
+ {
+ static const int md5sum_bin_len = 16;
+@@ -180,6 +183,7 @@
+
+ return md5sum_hex;
+ }
++#endif
+
+ #ifdef HAVE_SHA256
+ char *file_sha256sum_alloc(const char *file_name)
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1082,7 +1082,7 @@
+ conffile_list_elt_t *iter;
+ conffile_t *cf;
+ char *cf_backup;
+- char *md5sum;
++ char *chksum;
+
+ if (conf->noaction) return 0;
+
+@@ -1093,7 +1093,11 @@
+
+ /* Might need to initialize the md5sum for each conffile */
+ if (cf->value == NULL) {
++#ifdef HAVE_MD5
+ cf->value = file_md5sum_alloc(root_filename);
++#else
++ cf->value = file_sha256sum_alloc(root_filename);
++#endif
+ }
+
+ if (!file_exists(root_filename)) {
+@@ -1105,8 +1109,12 @@
+
+ if (file_exists(cf_backup)) {
+ /* Let's compute md5 to test if files are changed */
+- md5sum = file_md5sum_alloc(cf_backup);
+- if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) {
++#ifdef HAVE_MD5
++ chksum = file_md5sum_alloc(cf_backup);
++#else
++ chksum = file_sha256sum_alloc(cf_backup);
++#endif
++ if (chksum && cf->value && strcmp(cf->value,chksum) != 0 ) {
+ if (conf->force_maintainer) {
+ opkg_msg(NOTICE, "Conffile %s using maintainer's setting.\n",
+ cf_backup);
+@@ -1123,8 +1131,8 @@
+ }
+ }
+ unlink(cf_backup);
+- if (md5sum)
+- free(md5sum);
++ if (chksum)
++ free(chksum);
+ }
+
+ free(cf_backup);
+@@ -1323,6 +1331,7 @@
+ }
+ #endif
+
++#ifdef HAVE_MD5
+ /* Check for md5 values */
+ if (pkg->md5sum)
+ {
+@@ -1346,6 +1355,7 @@
+ if (file_md5)
+ free(file_md5);
+ }
++#endif
+
+ #ifdef HAVE_SHA256
+ /* Check for sha256 value */
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -25,13 +25,16 @@
+ pkg_src.c pkg_src.h pkg_src_list.c pkg_src_list.h \
+ str_list.c str_list.h void_list.c void_list.h \
+ active_list.c active_list.h list.h
+-opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \
++opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c \
+ parse_util.c parse_util.h \
+ sprintf_alloc.c sprintf_alloc.h \
+ xregex.c xregex.h xsystem.c xsystem.h
+ if HAVE_PATHFINDER
+ opkg_util_sources += opkg_pathfinder.c opkg_pathfinder.h
+ endif
++if HAVE_MD5
++opkg_util_sources += md5.c md5.h
++endif
+ if HAVE_SHA256
+ opkg_util_sources += sha256.c sha256.h
+ endif
+--- a/configure.ac
++++ b/configure.ac
+@@ -72,6 +72,7 @@
+ AC_DEFINE(HAVE_SHA256, 1, [Define if you want sha256 support])
+ fi
+ AM_CONDITIONAL(HAVE_SHA256, test "x$want_sha256" = "xyes")
++AM_CONDITIONAL(HAVE_MD5, test "x$want_sha256" = "xno")
+
+ # check for openssl
+ AC_ARG_ENABLE(openssl,
diff --git a/package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch b/package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch
new file mode 100644
index 0000000..8af4d40
--- /dev/null
+++ b/package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch
@@ -0,0 +1,31 @@
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1364,12 +1364,22 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+ file_sha256 = file_sha256sum_alloc(pkg->local_filename);
+ if (file_sha256 && strcmp(file_sha256, pkg->sha256sum))
+ {
+- opkg_msg(ERROR, "Package %s sha256sum mismatch. "
+- "Either the opkg or the package index are corrupt. "
+- "Try 'opkg update'.\n",
+- pkg->name);
+- free(file_sha256);
+- return -1;
++ if (!conf->force_checksum)
++ {
++ opkg_msg(ERROR,
++ "Package %s sha256sum mismatch. "
++ "Either the opkg or the package index are corrupt. "
++ "Try 'opkg update'.\n",
++ pkg->name);
++ free(file_sha256);
++ return -1;
++ }
++ else
++ {
++ opkg_msg(NOTICE,
++ "Ignored %s sha256sum mismatch.\n",
++ pkg->name);
++ }
+ }
+ if (file_sha256)
+ free(file_sha256);
diff --git a/package/system/opkg/patches/250-add-lists-dir-switch.patch b/package/system/opkg/patches/250-add-lists-dir-switch.patch
new file mode 100644
index 0000000..d0d0707
--- /dev/null
+++ b/package/system/opkg/patches/250-add-lists-dir-switch.patch
@@ -0,0 +1,39 @@
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -101,6 +101,8 @@ static struct option long_options[] = {
+ {"test", 0, 0, ARGS_OPT_NOACTION},
+ {"tmp-dir", 1, 0, 't'},
+ {"tmp_dir", 1, 0, 't'},
++ {"lists-dir", 1, 0, 'l'},
++ {"lists_dir", 1, 0, 'l'},
+ {"verbosity", 2, 0, 'V'},
+ {"version", 0, 0, 'v'},
+ {0, 0, 0, 0}
+@@ -115,7 +117,7 @@ args_parse(int argc, char *argv[])
+ char *tuple, *targ;
+
+ while (1) {
+- c = getopt_long_only(argc, argv, "Ad:f:ino:p:t:vV::",
++ c = getopt_long_only(argc, argv, "Ad:f:ino:p:l:t:vV::",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+@@ -139,6 +141,9 @@ args_parse(int argc, char *argv[])
+ case 't':
+ conf->tmp_dir = xstrdup(optarg);
+ break;
++ case 'l':
++ conf->lists_dir = xstrdup(optarg);
++ break;
+ case 'v':
+ printf("opkg version %s\n", VERSION);
+ exit(0);
+@@ -316,6 +321,8 @@ usage()
+ printf("\t automatically to satisfy dependencies\n");
+ printf("\t-t Specify tmp-dir.\n");
+ printf("\t--tmp-dir Specify tmp-dir.\n");
++ printf("\t-l Specify lists-dir.\n");
++ printf("\t--lists-dir Specify lists-dir.\n");
+
+ printf("\n");
+
diff --git a/package/system/opkg/patches/260-add-print-package-size.patch b/package/system/opkg/patches/260-add-print-package-size.patch
new file mode 100644
index 0000000..4dce356
--- /dev/null
+++ b/package/system/opkg/patches/260-add-print-package-size.patch
@@ -0,0 +1,74 @@
+--- a/libopkg/opkg_conf.c
++++ b/libopkg/opkg_conf.c
+@@ -69,6 +69,7 @@ opkg_option_t options[] = {
+ { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd },
+ { "proxy_user", OPKG_OPT_TYPE_STRING, &_conf.proxy_user },
+ { "query-all", OPKG_OPT_TYPE_BOOL, &_conf.query_all },
++ { "size", OPKG_OPT_TYPE_BOOL, &_conf.size },
+ { "tmp_dir", OPKG_OPT_TYPE_STRING, &_conf.tmp_dir },
+ { "verbosity", OPKG_OPT_TYPE_INT, &_conf.verbosity },
+ #if defined(HAVE_OPENSSL)
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -88,6 +88,7 @@ struct opkg_conf
+ int query_all;
+ int verbosity;
+ int noaction;
++ int size;
+ int download_only;
+ char *cache;
+
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -52,6 +52,7 @@ enum {
+ ARGS_OPT_AUTOREMOVE,
+ ARGS_OPT_CACHE,
+ ARGS_OPT_FORCE_SIGNATURE,
++ ARGS_OPT_SIZE,
+ };
+
+ static struct option long_options[] = {
+@@ -98,6 +99,7 @@ static struct option long_options[] = {
+ {"offline-root", 1, 0, 'o'},
+ {"add-arch", 1, 0, ARGS_OPT_ADD_ARCH},
+ {"add-dest", 1, 0, ARGS_OPT_ADD_DEST},
++ {"size", 0, 0, ARGS_OPT_SIZE},
+ {"test", 0, 0, ARGS_OPT_NOACTION},
+ {"tmp-dir", 1, 0, 't'},
+ {"tmp_dir", 1, 0, 't'},
+@@ -212,6 +214,9 @@ args_parse(int argc, char *argv[])
+ }
+ free(tuple);
+ break;
++ case ARGS_OPT_SIZE:
++ conf->size = 1;
++ break;
+ case ARGS_OPT_NOACTION:
+ conf->noaction = 1;
+ break;
+@@ -315,6 +320,7 @@ usage()
+ printf("\t--download-only No action -- download only\n");
+ printf("\t--nodeps Do not follow dependencies\n");
+ printf("\t--nocase Perform case insensitive pattern matching\n");
++ printf("\t--size Print package size when listing available packages\n");
+ printf("\t--force-removal-of-dependent-packages\n");
+ printf("\t Remove package and all dependencies\n");
+ printf("\t--autoremove Remove packages that were installed\n");
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -47,10 +47,12 @@ static void
+ print_pkg(pkg_t *pkg)
+ {
+ char *version = pkg_version_str_alloc(pkg);
++ printf("%s - %s", pkg->name, version);
++ if (conf->size)
++ printf(" - %lu", pkg->size);
+ if (pkg->description)
+- printf("%s - %s - %s\n", pkg->name, version, pkg->description);
+- else
+- printf("%s - %s\n", pkg->name, version);
++ printf(" - %s", pkg->description);
++ printf("\n");
+ free(version);
+ }
+
diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
new file mode 100644
index 0000000..d70cfd7
--- /dev/null
+++ b/package/system/procd/Makefile
@@ -0,0 +1,146 @@
+#
+# Copyright (C) 2014-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=procd
+PKG_VERSION:=2015-10-26
+
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://nbd.name/luci2/procd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=d5fddd91b966424bb63e943e789704d52382cc18
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
+
+PKG_CONFIG_DEPENDS:= CONFIG_KERNEL_SECCOMP CONFIG_NAND_SUPPORT CONFIG_PROCD_SHOW_BOOT CONFIG_PROCD_ZRAM_TMPFS \
+ CONFIG_KERNEL_NAMESPACES CONFIG_PACKAGE_procd-ujail CONFIG_PACKAGE_procd-seccomp
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+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
+ TITLE:=OpenWrt system process manager
+endef
+
+define Package/procd-ujail
+ SECTION:=base
+ CATEGORY:=Base system
+ DEPENDS:=@KERNEL_NAMESPACES +@KERNEL_UTS_NS +@KERNEL_IPC_NS +@KERNEL_PID_NS +libubox +libblobmsg-json
+ TITLE:=OpenWrt process jail helper
+endef
+
+define Package/procd-seccomp
+ SECTION:=base
+ CATEGORY:=Base system
+ DEPENDS:=@arm||@armeb||@mips||@mipsel||@i386||@x86_64 @!TARGET_uml @KERNEL_SECCOMP +libubox +libblobmsg-json
+ 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
+
+config PROCD_SHOW_BOOT
+ bool
+ default n
+ prompt "Print the shutdown to the console as well as logging it to syslog"
+
+config PROCD_ZRAM_TMPFS
+ bool
+ default n
+ prompt "Mount /tmp using zram."
+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
+
+ifeq ($(CONFIG_PROCD_ZRAM_TMPFS),y)
+ CMAKE_OPTIONS += -DZRAM_TMPFS=1
+endif
+
+ifdef CONFIG_PACKAGE_procd-ujail
+ CMAKE_OPTIONS += -DJAIL_SUPPORT=1
+endif
+
+ifdef CONFIG_PACKAGE_procd-seccomp
+ CMAKE_OPTIONS += -DSECCOMP_SUPPORT=1 -DUTRACE_SUPPORT=1
+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_DATA) $(PKG_INSTALL_DIR)/usr/lib/libsetlbf.so $(1)/lib
+ $(INSTALL_BIN) ./files/reload_config $(1)/sbin/
+ $(INSTALL_DATA) ./files/hotplug*.json $(1)/etc/
+ $(INSTALL_DATA) ./files/procd.sh $(1)/lib/functions/
+endef
+
+define Package/procd-ujail/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ujail $(1)/sbin/
+endef
+
+define Package/procd-seccomp/install
+ $(INSTALL_DIR) $(1)/sbin $(1)/lib
+ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libpreload-seccomp.so $(1)/lib
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/utrace $(1)/sbin/
+ $(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/hotplug-preinit.json b/package/system/procd/files/hotplug-preinit.json
new file mode 100644
index 0000000..614b104
--- /dev/null
+++ b/package/system/procd/files/hotplug-preinit.json
@@ -0,0 +1,20 @@
+[
+ [ "case", "ACTION", {
+ "add": [
+ [ "if",
+ [ "has", "FIRMWARE" ],
+ [
+ [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
+ [ "load-firmware", "/lib/firmware" ],
+ [ "return" ]
+ ]
+ ],
+ ],
+ }, ],
+ [ "if",
+ [ "and",
+ [ "eq", "SUBSYSTEM", "button" ],
+ ],
+ [ "exec", "/etc/rc.button/failsafe" ]
+ ],
+]
diff --git a/package/system/procd/files/hotplug.json b/package/system/procd/files/hotplug.json
new file mode 100644
index 0000000..27b4836
--- /dev/null
+++ b/package/system/procd/files/hotplug.json
@@ -0,0 +1,86 @@
+[
+ [ "case", "ACTION", {
+ "add": [
+ [ "if",
+ [ "and",
+ [ "has", "MAJOR" ],
+ [ "has", "MINOR" ],
+ ],
+ [
+ [ "if",
+ [ "or",
+ [ "eq", "DEVNAME",
+ [ "null", "full", "ptmx", "zero" ],
+ ],
+ [ "regex", "DEVNAME",
+ [ "^gpio", "^hvc" ],
+ ],
+ ],
+ [
+ [ "makedev", "/dev/%DEVNAME%", "0666" ],
+ [ "return" ],
+ ]
+ ],
+ [ "if",
+ [ "or",
+ [ "eq", "DEVNAME", "mapper/control" ],
+ [ "regex", "DEVPATH", "^ppp" ],
+ ],
+ [
+ [ "makedev", "/dev/%DEVNAME%", "0600" ],
+ [ "return" ],
+ ],
+ ],
+ [ "if",
+ [ "has", "DEVNAME" ],
+ [ "makedev", "/dev/%DEVNAME%", "0644" ],
+ ],
+ ],
+ ],
+ [ "if",
+ [ "has", "FIRMWARE" ],
+ [
+ [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
+ [ "load-firmware", "/lib/firmware" ],
+ [ "return" ]
+ ]
+ ],
+ ],
+ "remove" : [
+ [ "if",
+ [ "and",
+ [ "has", "DEVNAME" ],
+ [ "has", "MAJOR" ],
+ [ "has", "MINOR" ],
+ ],
+ [ "rm", "/dev/%DEVNAME%" ]
+ ]
+ ]
+ } ],
+ [ "if",
+ [ "eq", "SUBSYSTEM", "platform" ],
+ [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ]
+ ],
+ [ "if",
+ [ "and",
+ [ "has", "BUTTON" ],
+ [ "eq", "SUBSYSTEM", "button" ],
+ ],
+ [ "button", "/etc/rc.button/%BUTTON%" ]
+ ],
+ [ "if",
+ [ "eq", "SUBSYSTEM",
+ [ "net", "input", "usb", "usbmisc", "ieee1394", "block", "atm", "zaptel", "tty", "button" ]
+ ],
+ [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ]
+ ],
+ [ "if",
+ [ "and",
+ [ "eq", "SUBSYSTEM", "usb-serial" ],
+ [ "regex", "DEVNAME",
+ [ "^ttyUSB", "^ttyACM" ]
+ ],
+ ],
+ [ "exec", "/sbin/hotplug-call", "tty" ]
+ ],
+]
diff --git a/package/system/procd/files/nand-preinit.sh b/package/system/procd/files/nand-preinit.sh
new file mode 100644
index 0000000..cf59624
--- /dev/null
+++ b/package/system/procd/files/nand-preinit.sh
@@ -0,0 +1,21 @@
+#!/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
new file mode 100644
index 0000000..3b1c749
--- /dev/null
+++ b/package/system/procd/files/nand.sh
@@ -0,0 +1,361 @@
+#!/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"
+ 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"
+ 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_upgrade_tar() {
+ local tar_file="$1"
+ local board_name="$(cat /tmp/sysinfo/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)
+
+ [ ! "$(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 "{\"path\": \"$path\" }"
+ exit 0
+ }
+}
+append sysupgrade_pre_upgrade nand_upgrade_stage1
+
+# 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
+ cp /sbin/upgraded /tmp/
+ nand_upgrade_stage1
+}
diff --git a/package/system/procd/files/procd.sh b/package/system/procd/files/procd.sh
new file mode 100644
index 0000000..e83e75c
--- /dev/null
+++ b/package/system/procd/files/procd.sh
@@ -0,0 +1,430 @@
+# procd API:
+#
+# procd_open_service(name, [script]):
+# Initialize a new procd command message containing a service with one or more instances
+#
+# procd_close_service()
+# Send the command message for the service
+#
+# procd_open_instance([name]):
+# Add an instance to the service described by the previous procd_open_service call
+#
+# procd_set_param(type, [value...])
+# Available types:
+# command: command line (array).
+# respawn info: array with 3 values $fail_threshold $restart_timeout $max_fail
+# env: environment variable (passed to the process)
+# data: arbitrary name/value pairs for detecting config changes (table)
+# file: configuration files (array)
+# netdev: bound network device (detects ifindex changes)
+# limits: resource limits (passed to the process)
+# user info: array with 1 values $username
+#
+# No space separation is done for arrays/tables - use one function argument per command line argument
+#
+# procd_close_instance():
+# Complete the instance being prepared
+#
+# procd_kill(service, [instance]):
+# Kill a service instance (or all instances)
+#
+
+. $IPKG_INSTROOT/usr/share/libubox/jshn.sh
+
+_PROCD_SERVICE=
+
+_procd_call() {
+ local old_cb
+
+ json_set_namespace procd old_cb
+ "$@"
+ json_set_namespace $old_cb
+}
+
+_procd_wrapper() {
+ while [ -n "$1" ]; do
+ eval "$1() { _procd_call _$1 \"\$@\"; }"
+ shift
+ done
+}
+
+_procd_ubus_call() {
+ local cmd="$1"
+
+ [ -n "$PROCD_DEBUG" ] && json_dump >&2
+ ubus call service "$cmd" "$(json_dump)"
+ json_cleanup
+}
+
+_procd_open_service() {
+ local name="$1"
+ local script="$2"
+
+ _PROCD_SERVICE="$name"
+ _PROCD_INSTANCE_SEQ=0
+
+ json_init
+ json_add_string name "$name"
+ [ -n "$script" ] && json_add_string script "$script"
+ json_add_object instances
+}
+
+_procd_close_service() {
+ json_close_object
+ service_triggers
+ _procd_ubus_call set
+}
+
+_procd_add_array_data() {
+ while [ "$#" -gt 0 ]; do
+ json_add_string "" "$1"
+ shift
+ done
+}
+
+_procd_add_array() {
+ json_add_array "$1"
+ shift
+ _procd_add_array_data "$@"
+ json_close_array
+}
+
+_procd_add_table_data() {
+ while [ -n "$1" ]; do
+ local var="${1%%=*}"
+ local val="${1#*=}"
+ [ "$1" = "$val" ] && val=
+ json_add_string "$var" "$val"
+ shift
+ done
+}
+
+_procd_add_table() {
+ json_add_object "$1"
+ shift
+ _procd_add_table_data "$@"
+ json_close_object
+}
+
+_procd_open_instance() {
+ local name="$1"; shift
+
+ _PROCD_INSTANCE_SEQ="$(($_PROCD_INSTANCE_SEQ + 1))"
+ name="${name:-instance$_PROCD_INSTANCE_SEQ}"
+ json_add_object "$name"
+ [ -n "$TRACE_SYSCALLS" ] && json_add_boolean trace "1"
+}
+
+_procd_open_trigger() {
+ json_add_array "triggers"
+}
+
+_procd_open_validate() {
+ json_add_array "validate"
+}
+
+_procd_add_jail() {
+ json_add_object "jail"
+ json_add_string name "$1"
+ json_add_string root "/tmp/.jail/$1"
+
+ shift
+
+ for a in $@; do
+ case $a in
+ log) json_add_boolean "log" "1";;
+ ubus) json_add_boolean "ubus" "1";;
+ procfs) json_add_boolean "procfs" "1";;
+ sysfs) json_add_boolean "sysfs" "1";;
+ esac
+ done
+ json_add_object "mount"
+ json_close_object
+ json_close_object
+}
+
+_procd_add_jail_mount() {
+ local _json_no_warning=1
+
+ json_select "jail"
+ [ $? = 0 ] || return
+ json_select "mount"
+ [ $? = 0 ] || {
+ json_select ..
+ return
+ }
+ for a in $@; do
+ json_add_string "$a" "0"
+ done
+ json_select ..
+ json_select ..
+}
+
+_procd_add_jail_mount_rw() {
+ local _json_no_warning=1
+
+ json_select "jail"
+ [ $? = 0 ] || return
+ json_select "mount"
+ [ $? = 0 ] || {
+ json_select ..
+ return
+ }
+ for a in $@; do
+ json_add_string "$a" "1"
+ done
+ json_select ..
+ json_select ..
+}
+
+_procd_set_param() {
+ local type="$1"; shift
+
+ case "$type" in
+ env|data|limits)
+ _procd_add_table "$type" "$@"
+ ;;
+ command|netdev|file|respawn|watch)
+ _procd_add_array "$type" "$@"
+ ;;
+ error)
+ json_add_array "$type"
+ json_add_string "" "$@"
+ json_close_array
+ ;;
+ nice)
+ json_add_int "$type" "$1"
+ ;;
+ user|seccomp)
+ json_add_string "$type" "$1"
+ ;;
+ stdout|stderr)
+ json_add_boolean "$type" "$1"
+ ;;
+ esac
+}
+
+_procd_add_interface_trigger() {
+ json_add_array
+ _procd_add_array_data "$1"
+ shift
+
+ json_add_array
+ _procd_add_array_data "if"
+
+ json_add_array
+ _procd_add_array_data "eq" "interface" "$1"
+ shift
+ json_close_array
+
+ json_add_array
+ _procd_add_array_data "run_script" "$@"
+ json_close_array
+
+ json_close_array
+ json_close_array
+}
+
+_procd_add_reload_interface_trigger() {
+ local script=$(readlink "$initscript")
+ local name=$(basename ${script:-$initscript})
+
+ _procd_open_trigger
+ _procd_add_interface_trigger "interface.*" $1 /etc/init.d/$name reload
+ _procd_close_trigger
+}
+
+_procd_add_config_trigger() {
+ json_add_array
+ _procd_add_array_data "$1"
+ shift
+
+ json_add_array
+ _procd_add_array_data "if"
+
+ json_add_array
+ _procd_add_array_data "eq" "package" "$1"
+ shift
+ json_close_array
+
+ json_add_array
+ _procd_add_array_data "run_script" "$@"
+ json_close_array
+
+ json_close_array
+
+ json_close_array
+}
+
+_procd_add_raw_trigger() {
+ json_add_array
+ _procd_add_array_data "$1"
+ shift
+ local timeout=$1
+ shift
+
+ json_add_array
+ json_add_array
+ _procd_add_array_data "run_script" "$@"
+ json_close_array
+ json_close_array
+
+ json_add_int "" "$timeout"
+
+ json_close_array
+}
+
+_procd_add_reload_trigger() {
+ local script=$(readlink "$initscript")
+ local name=$(basename ${script:-$initscript})
+ local file
+
+ _procd_open_trigger
+ for file in "$@"; do
+ _procd_add_config_trigger "config.change" "$file" /etc/init.d/$name reload
+ done
+ _procd_close_trigger
+}
+
+_procd_add_validation() {
+ _procd_open_validate
+ $@
+ _procd_close_validate
+}
+
+_procd_append_param() {
+ local type="$1"; shift
+ local _json_no_warning=1
+
+ json_select "$type"
+ [ $? = 0 ] || {
+ _procd_set_param "$type" "$@"
+ return
+ }
+ case "$type" in
+ env|data|limits)
+ _procd_add_table_data "$@"
+ ;;
+ command|netdev|file|respawn|watch)
+ _procd_add_array_data "$@"
+ ;;
+ error)
+ json_add_string "" "$@"
+ ;;
+ esac
+ json_select ..
+}
+
+_procd_close_instance() {
+ json_close_object
+}
+
+_procd_close_trigger() {
+ json_close_array
+}
+
+_procd_close_validate() {
+ json_close_array
+}
+
+_procd_add_instance() {
+ _procd_open_instance
+ _procd_set_param command "$@"
+ _procd_close_instance
+}
+
+_procd_kill() {
+ local service="$1"
+ local instance="$2"
+
+ json_init
+ [ -n "$service" ] && json_add_string name "$service"
+ [ -n "$instance" ] && json_add_string instance "$instance"
+ _procd_ubus_call delete
+}
+
+procd_open_data() {
+ local name="$1"
+ json_set_namespace procd __procd_old_cb
+ json_add_object data
+}
+
+procd_close_data() {
+ json_close_object
+ json_set_namespace $__procd_old_cb
+}
+
+_procd_set_config_changed() {
+ local package="$1"
+
+ json_init
+ json_add_string type config.change
+ json_add_object data
+ json_add_string package "$package"
+ json_close_object
+
+ ubus call service event "$(json_dump)"
+}
+
+procd_add_mdns_service() {
+ local service proto port
+ service=$1; shift
+ proto=$1; shift
+ port=$1; shift
+ json_add_object "${service}_$port"
+ json_add_string "service" "_$service._$proto.local"
+ json_add_int port "$port"
+ [ -n "$1" ] && {
+ json_add_array txt
+ for txt in $@; do json_add_string "" $txt; done
+ json_select ..
+ }
+ json_select ..
+}
+
+procd_add_mdns() {
+ procd_open_data
+ json_add_object "mdns"
+ procd_add_mdns_service $@
+ json_close_object
+ procd_close_data
+}
+
+uci_validate_section()
+{
+ local _package="$1"
+ local _type="$2"
+ local _name="$3"
+ local _result
+ local _error
+ shift; shift; shift
+ _result=`/sbin/validate_data "$_package" "$_type" "$_name" "$@" 2> /dev/null`
+ _error=$?
+ eval "$_result"
+ [ "$_error" = "0" ] || `/sbin/validate_data "$_package" "$_type" "$_name" "$@" 1> /dev/null`
+ return $_error
+}
+
+_procd_wrapper \
+ procd_open_service \
+ procd_close_service \
+ procd_add_instance \
+ procd_add_raw_trigger \
+ procd_add_config_trigger \
+ procd_add_interface_trigger \
+ procd_add_reload_trigger \
+ procd_add_reload_interface_trigger \
+ procd_open_trigger \
+ procd_close_trigger \
+ procd_open_instance \
+ procd_close_instance \
+ procd_open_validate \
+ procd_close_validate \
+ procd_add_jail \
+ procd_add_jail_mount \
+ procd_add_jail_mount_rw \
+ procd_set_param \
+ procd_append_param \
+ procd_add_validation \
+ procd_set_config_changed \
+ procd_kill
diff --git a/package/system/procd/files/reload_config b/package/system/procd/files/reload_config
new file mode 100644
index 0000000..8d1cdb1
--- /dev/null
+++ b/package/system/procd/files/reload_config
@@ -0,0 +1,15 @@
+#!/bin/sh
+rm -rf /var/run/config.check
+mkdir -p /var/run/config.check
+for config in /etc/config/*; do
+ file=${config##*/}
+ uci show "${file##*/}" > /var/run/config.check/$file
+done
+MD5FILE=/var/run/config.md5
+[ -f $MD5FILE ] && {
+ for c in `md5sum -c $MD5FILE 2>/dev/null| grep FAILED | cut -d: -f1`; do
+ ubus call service event "{ \"type\": \"config.change\", \"data\": { \"package\": \"$(basename $c)\" }}"
+ done
+}
+md5sum /var/run/config.check/* > $MD5FILE
+rm -rf /var/run/config.check
diff --git a/package/system/rpcd/Makefile b/package/system/rpcd/Makefile
new file mode 100644
index 0000000..dc7284a
--- /dev/null
+++ b/package/system/rpcd/Makefile
@@ -0,0 +1,97 @@
+#
+# Copyright (C) 2013-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=rpcd
+PKG_VERSION:=2015-01-10
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://nbd.name/luci2/rpcd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)
+PKG_SOURCE_VERSION:=f00890cd6eb47ad9bb5da0fb6c50aedc8406e7c5
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+PKG_MAINTAINER:=Jo-Philipp Wich <jow@openwrt.org>
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(1)/usr/include
+ $(CP) $(PKG_BUILD_DIR)/include/rpcd $(1)/usr/include/
+endef
+
+define Package/rpcd/default
+ SECTION:=utils
+ CATEGORY:=Base system
+ TITLE:=OpenWrt ubus RPC backend server
+ DEPENDS:=+libubus +libubox
+endef
+
+define Package/rpcd
+ $(Package/rpcd/default)
+ DEPENDS+= +libuci +libblobmsg-json
+endef
+
+define Package/rpcd/description
+ This package provides the UBUS RPC backend server to expose various
+ functionality to frontend programs via JSON-RPC.
+endef
+
+define Package/rpcd/conffiles
+/etc/config/rpcd
+endef
+
+define Package/rpcd/install
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/rpcd.init $(1)/etc/init.d/rpcd
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd $(1)/sbin/rpcd
+ $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/unauthenticated.json $(1)/usr/share/rpcd/acl.d/unauthenticated.json
+ $(INSTALL_DIR) $(1)/etc/config
+ $(INSTALL_CONF) ./files/rpcd.config $(1)/etc/config/rpcd
+endef
+
+
+# 1: plugin name
+# 2: extra dependencies
+# 3: plugin title/description
+define BuildPlugin
+
+ PKG_CONFIG_DEPENDS += CONFIG_PACKAGE_luci-rpc-mod-$(1)
+
+ define Package/rpcd-mod-$(1)
+ $(Package/rpcd/default)
+ TITLE+= ($(1) plugin)
+ DEPENDS+=rpcd $(2)
+ endef
+
+ define Package/rpcd-mod-$(1)/description
+ $(3)
+ endef
+
+ define Package/rpcd-mod-$(1)/install
+ $(INSTALL_DIR) $$(1)/usr/lib/rpcd
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(1).so $$(1)/usr/lib/rpcd/
+ endef
+
+ $$(eval $$(call BuildPackage,rpcd-mod-$(1)))
+
+endef
+
+$(eval $(call BuildPackage,rpcd))
+$(eval $(call BuildPlugin,file,,Provides ubus calls for file and directory operations.))
+$(eval $(call BuildPlugin,rpcsys,,Provides ubus calls for sysupgrade and password changing.))
+$(eval $(call BuildPlugin,iwinfo,+libiwinfo,Provides ubus calls for accessing iwinfo data.))
diff --git a/package/system/rpcd/files/rpcd.config b/package/system/rpcd/files/rpcd.config
new file mode 100644
index 0000000..499ea27
--- /dev/null
+++ b/package/system/rpcd/files/rpcd.config
@@ -0,0 +1,7 @@
+
+config login
+ option username 'root'
+ option password '$p$root'
+ list read '*'
+ list write '*'
+
diff --git a/package/system/rpcd/files/rpcd.init b/package/system/rpcd/files/rpcd.init
new file mode 100755
index 0000000..98b6333
--- /dev/null
+++ b/package/system/rpcd/files/rpcd.init
@@ -0,0 +1,21 @@
+#!/bin/sh /etc/rc.common
+
+START=12
+
+USE_PROCD=1
+NAME=rpcd
+PROG=/sbin/rpcd
+
+start_service() {
+ procd_open_instance
+ procd_set_param command "$PROG"
+ procd_close_instance
+}
+
+stop() {
+ service_stop /sbin/rpcd
+}
+
+reload() {
+ service_reload /sbin/rpcd
+}
diff --git a/package/system/ubox/Makefile b/package/system/ubox/Makefile
new file mode 100644
index 0000000..a85a3c9
--- /dev/null
+++ b/package/system/ubox/Makefile
@@ -0,0 +1,46 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ubox
+PKG_VERSION:=2015-07-14
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://nbd.name/luci2/ubox.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=907d046c8929fb74e5a3502a9498198695e62ad8
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+CMAKE_INSTALL:=1
+PKG_CHECK_FORMAT_SECURITY:=0
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+TARGET_LDFLAGS += $(if $(CONFIG_USE_GLIBC),-lrt)
+
+define Package/ubox
+ SECTION:=base
+ CATEGORY:=Base system
+ DEPENDS:=+libubox +ubusd +ubus +libubus +libuci +USE_GLIBC:librt
+ TITLE:=OpenWrt system helper toolbox
+endef
+
+define Package/ubox/install
+ $(INSTALL_DIR) $(1)/sbin $(1)/usr/sbin $(1)/lib/ $(1)/etc/init.d/
+
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{kmodloader,logd,logread,validate_data} $(1)/sbin/
+ $(INSTALL_BIN) ./files/log.init $(1)/etc/init.d/log
+ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libvalidate.so $(1)/lib
+
+ $(LN) ../../sbin/kmodloader $(1)/usr/sbin/rmmod
+ $(LN) ../../sbin/kmodloader $(1)/usr/sbin/insmod
+ $(LN) ../../sbin/kmodloader $(1)/usr/sbin/lsmod
+ $(LN) ../../sbin/kmodloader $(1)/usr/sbin/modinfo
+ $(LN) ../../sbin/kmodloader $(1)/usr/sbin/modprobe
+endef
+
+$(eval $(call BuildPackage,ubox))
diff --git a/package/system/ubox/files/log.init b/package/system/ubox/files/log.init
new file mode 100644
index 0000000..4fc00d5
--- /dev/null
+++ b/package/system/ubox/files/log.init
@@ -0,0 +1,98 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2013 OpenWrt.org
+
+# start after and stop before networking
+START=12
+STOP=89
+PIDCOUNT=0
+
+USE_PROCD=1
+PROG=/sbin/logread
+
+validate_log_section()
+{
+ uci_validate_section system system "${1}" \
+ 'log_file:string' \
+ 'log_size:uinteger' \
+ 'log_ip:ipaddr' \
+ 'log_remote:bool:1' \
+ 'log_port:port:514' \
+ 'log_proto:or("tcp", "udp"):udp' \
+ 'log_trailer_null:bool:0' \
+ 'log_prefix:string'
+}
+
+validate_log_daemon()
+{
+ uci_validate_section system system "${1}" \
+ 'log_size:uinteger:0' \
+ 'log_buffer_size:uinteger:0'
+}
+
+start_service_daemon()
+{
+ local log_buffer_size log_size
+ validate_log_daemon "${1}"
+ [ $log_buffer_size -eq 0 -a $log_size -gt 0 ] && log_buffer_size=$log_size
+ [ $log_buffer_size -eq 0 ] && log_buffer_size=16
+ procd_open_instance
+ procd_set_param command "/sbin/logd"
+ procd_append_param command -S "${log_buffer_size}"
+ procd_set_param respawn
+ procd_close_instance
+}
+
+start_service_file()
+{
+ PIDCOUNT="$(( ${PIDCOUNT} + 1))"
+ local pid_file="/var/run/logread.${PIDCOUNT}.pid"
+ local log_file log_size
+
+ validate_log_section "${1}" || {
+ echo "validation failed"
+ return 1
+ }
+ [ -z "${log_file}" ] && return
+
+ procd_open_instance
+ procd_set_param command "$PROG" -f -F "$log_file" -p "$pid_file"
+ [ -n "${log_size}" ] && procd_append_param command -S "$log_size"
+ procd_close_instance
+}
+
+start_service_remote()
+{
+ PIDCOUNT="$(( ${PIDCOUNT} + 1))"
+ local pid_file="/var/run/logread.${PIDCOUNT}.pid"
+ local log_ip log_port log_proto log_prefix log_remote log_trailer_null
+
+ validate_log_section "${1}" || {
+ echo "validation failed"
+ return 1
+ }
+ [ "${log_remote}" -ne 0 ] || return
+ [ -z "${log_ip}" ] && return
+
+ procd_open_instance
+ procd_set_param command "$PROG" -f -r "$log_ip" "${log_port}" -p "$pid_file"
+ case "${log_proto}" in
+ "udp") procd_append_param command -u;;
+ "tcp") [ "${log_trailer_null}" -eq 1 ] && procd_append_param command -0;;
+ esac
+ [ -z "${log_prefix}" ] || procd_append_param command -P "${log_prefix}"
+ procd_close_instance
+}
+
+service_triggers()
+{
+ procd_add_reload_trigger "system"
+ procd_add_validation validate_log_section
+}
+
+start_service()
+{
+ config_load system
+ config_foreach start_service_daemon system
+ config_foreach start_service_file system
+ config_foreach start_service_remote system
+}
diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile
new file mode 100644
index 0000000..c34c5cc
--- /dev/null
+++ b/package/system/ubus/Makefile
@@ -0,0 +1,80 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ubus
+PKG_VERSION:=2015-07-07
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=http://git.openwrt.org/project/ubus.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=7ec9b8dec77b969bfc860995f96fe91fd40ba5e4
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+PKG_MIRROR_MD5SUM:=
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/ubus
+ SECTION:=base
+ CATEGORY:=Base system
+ DEPENDS:=+libubus +libblobmsg-json +ubusd
+ TITLE:=OpenWrt RPC client utility
+endef
+
+define Package/ubusd
+ SECTION:=base
+ CATEGORY:=Base system
+ TITLE:=OpenWrt RPC daemon
+ DEPENDS:=+libubox +libblobmsg-json
+endef
+
+define Package/libubus
+ SECTION:=libs
+ CATEGORY:=Libraries
+ DEPENDS:=+libubox
+ ABI_VERSION:=$(PKG_VERSION)
+ TITLE:=OpenWrt RPC client library
+endef
+
+define Package/libubus-lua
+ SECTION:=libs
+ CATEGORY:=Libraries
+ DEPENDS:=+libubus +liblua
+ TITLE:=Lua binding for the OpenWrt RPC client
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+CMAKE_OPTIONS = \
+ -DLUAPATH=/usr/lib/lua
+
+define Package/ubus/install
+ $(INSTALL_DIR) $(1)/bin
+ $(CP) $(PKG_INSTALL_DIR)/usr/bin/ubus $(1)/bin/
+endef
+
+define Package/ubusd/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(CP) $(PKG_INSTALL_DIR)/usr/sbin/ubusd $(1)/sbin/
+endef
+
+define Package/libubus/install
+ $(INSTALL_DIR) $(1)/lib
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so $(1)/lib/
+endef
+
+define Package/libubus-lua/install
+ $(INSTALL_DIR) $(1)/usr/lib/lua
+ $(CP) $(PKG_BUILD_DIR)/lua/ubus.so $(1)/usr/lib/lua/
+endef
+
+$(eval $(call BuildPackage,libubus))
+$(eval $(call BuildPackage,libubus-lua))
+$(eval $(call BuildPackage,ubus))
+$(eval $(call BuildPackage,ubusd))
diff --git a/package/system/uci/Makefile b/package/system/uci/Makefile
new file mode 100644
index 0000000..247b470
--- /dev/null
+++ b/package/system/uci/Makefile
@@ -0,0 +1,92 @@
+#
+# Copyright (C) 2008-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+UCI_VERSION=2015-08-27
+UCI_RELEASE=1
+
+PKG_NAME:=uci
+PKG_VERSION:=$(UCI_VERSION)$(if $(UCI_RELEASE),.$(UCI_RELEASE))
+PKG_RELEASE:=1
+PKG_REV:=2cd94fd505b293e657278e31deb32a7d66d20714
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=git://nbd.name/uci.git
+PKG_SOURCE_SUBDIR:=uci-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_PROTO:=git
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+
+PKG_BUILD_PARALLEL:=0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+# set to 1 to enable debugging
+DEBUG=
+
+define Package/libuci
+ SECTION:=libs
+ CATEGORY:=Libraries
+ TITLE:=C library for the Unified Configuration Interface (UCI)
+ DEPENDS:=+libubox
+endef
+
+define Package/uci
+ SECTION:=base
+ CATEGORY:=Base system
+ DEPENDS:=+libuci
+ TITLE:=Utility for the Unified Configuration Interface (UCI)
+endef
+
+define Package/libuci-lua
+ SECTION=libs
+ CATEGORY=Libraries
+ DEPENDS:=+libuci +liblua
+ TITLE:=Lua plugin for UCI
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+TARGET_LDFLAGS += -L$(STAGING_DIR)/usr/lib
+
+CMAKE_OPTIONS = \
+ -DLUAPATH=/usr/lib/lua \
+ $(if $(DEBUG),-DUCI_DEBUG=ON)
+
+define Package/libuci/install
+ $(INSTALL_DIR) $(1)/lib
+ $(CP) $(PKG_BUILD_DIR)/libuci.so* $(1)/lib/
+endef
+
+define Package/libuci-lua/install
+ $(INSTALL_DIR) $(1)/usr/lib/lua
+ $(CP) $(PKG_BUILD_DIR)/lua/uci.so $(1)/usr/lib/lua/
+endef
+
+define Package/uci/install
+ $(INSTALL_DIR) $(1)/etc/uci-defaults
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/uci $(1)/sbin/
+ $(CP) ./files/* $(1)/
+endef
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(1)/usr/include
+ $(CP) $(PKG_BUILD_DIR)/uci{,_config,_blob,map}.h $(1)/usr/include
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(CP) $(PKG_BUILD_DIR)/libuci.so* $(1)/usr/lib
+ $(CP) $(PKG_BUILD_DIR)/libucimap.a $(1)/usr/lib
+endef
+
+$(eval $(call BuildPackage,uci))
+$(eval $(call BuildPackage,libuci))
+$(eval $(call BuildPackage,libuci-lua))
diff --git a/package/system/uci/files/lib/config/uci.sh b/package/system/uci/files/lib/config/uci.sh
new file mode 100644
index 0000000..db84c83
--- /dev/null
+++ b/package/system/uci/files/lib/config/uci.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+# Shell script compatibility wrappers for /sbin/uci
+#
+# Copyright (C) 2008-2010 OpenWrt.org
+# Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+CONFIG_APPEND=
+uci_load() {
+ local PACKAGE="$1"
+ local DATA
+ local RET
+ local VAR
+
+ _C=0
+ if [ -z "$CONFIG_APPEND" ]; then
+ for VAR in $CONFIG_LIST_STATE; do
+ export ${NO_EXPORT:+-n} CONFIG_${VAR}=
+ export ${NO_EXPORT:+-n} CONFIG_${VAR}_LENGTH=
+ done
+ export ${NO_EXPORT:+-n} CONFIG_LIST_STATE=
+ export ${NO_EXPORT:+-n} CONFIG_SECTIONS=
+ export ${NO_EXPORT:+-n} CONFIG_NUM_SECTIONS=0
+ export ${NO_EXPORT:+-n} CONFIG_SECTION=
+ fi
+
+ DATA="$(/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} ${LOAD_STATE:+-P /var/state} -S -n export "$PACKAGE" 2>/dev/null)"
+ RET="$?"
+ [ "$RET" != 0 -o -z "$DATA" ] || eval "$DATA"
+ unset DATA
+
+ ${CONFIG_SECTION:+config_cb}
+ return "$RET"
+}
+
+uci_set_default() {
+ local PACKAGE="$1"
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -q show "$PACKAGE" > /dev/null && return 0
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} import "$PACKAGE"
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} commit "$PACKAGE"
+}
+
+uci_revert_state() {
+ local PACKAGE="$1"
+ local CONFIG="$2"
+ local OPTION="$3"
+
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state revert "$PACKAGE${CONFIG:+.$CONFIG}${OPTION:+.$OPTION}"
+}
+
+uci_set_state() {
+ local PACKAGE="$1"
+ local CONFIG="$2"
+ local OPTION="$3"
+ local VALUE="$4"
+
+ [ "$#" = 4 ] || return 0
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state set "$PACKAGE.$CONFIG${OPTION:+.$OPTION}=$VALUE"
+}
+
+uci_toggle_state() {
+ uci_revert_state "$1" "$2" "$3"
+ uci_set_state "$1" "$2" "$3" "$4"
+}
+
+uci_set() {
+ local PACKAGE="$1"
+ local CONFIG="$2"
+ local OPTION="$3"
+ local VALUE="$4"
+
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} set "$PACKAGE.$CONFIG.$OPTION=$VALUE"
+}
+
+uci_get_state() {
+ uci_get "$1" "$2" "$3" "$4" "/var/state"
+}
+
+uci_get() {
+ local PACKAGE="$1"
+ local CONFIG="$2"
+ local OPTION="$3"
+ local DEFAULT="$4"
+ local STATE="$5"
+
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} ${STATE:+-P $STATE} -q get "$PACKAGE${CONFIG:+.$CONFIG}${OPTION:+.$OPTION}"
+ RET="$?"
+ [ "$RET" -ne 0 ] && [ -n "$DEFAULT" ] && echo "$DEFAULT"
+ return "$RET"
+}
+
+uci_add() {
+ local PACKAGE="$1"
+ local TYPE="$2"
+ local CONFIG="$3"
+
+ if [ -z "$CONFIG" ]; then
+ export ${NO_EXPORT:+-n} CONFIG_SECTION="$(/sbin/uci add "$PACKAGE" "$TYPE")"
+ else
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} set "$PACKAGE.$CONFIG=$TYPE"
+ export ${NO_EXPORT:+-n} CONFIG_SECTION="$CONFIG"
+ fi
+}
+
+uci_rename() {
+ local PACKAGE="$1"
+ local CONFIG="$2"
+ local VALUE="$3"
+
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} rename "$PACKAGE.$CONFIG=$VALUE"
+}
+
+uci_remove() {
+ local PACKAGE="$1"
+ local CONFIG="$2"
+ local OPTION="$3"
+
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} del "$PACKAGE.$CONFIG${OPTION:+.$OPTION}"
+}
+
+uci_commit() {
+ local PACKAGE="$1"
+ /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} commit $PACKAGE
+}
diff --git a/package/system/udev/Config.in b/package/system/udev/Config.in
new file mode 100644
index 0000000..a9f3e00
--- /dev/null
+++ b/package/system/udev/Config.in
@@ -0,0 +1,117 @@
+# udev package config
+
+menu "Configuration"
+ depends on PACKAGE_udev
+
+config UDEV_DISABLE_LOGGING
+ bool "Disable udev logging to syslog"
+ default n
+ help
+ Disable logging of udev messages to the syslog. If
+ unsure, choose the default N.
+
+config UDEV_ENABLE_DEBUG
+ bool "Enable debug build of the udev package"
+ default n
+ help
+ Compile in udev debug messages. If unsure, choose
+ the default N.
+
+config UDEV_EXTRA_accelerometer
+ bool "Install udev accelerometer callout"
+ default y
+ help
+ accelerometer - udev callout to export device orientation
+ through property
+
+config UDEV_EXTRA_ata_id
+ bool "Install udev ata_id callout"
+ default y
+ help
+ ata_id - udev callout to read product/serial number
+ from ATA drives
+
+config UDEV_EXTRA_cdrom_id
+ bool "Install udev cdrom_id callout"
+ default y
+ help
+ cdrom_id - udev callout to determine the capabilities
+ of optical drives and media
+
+config UDEV_EXTRA_collect
+ bool "Install udev collect"
+ default n
+ help
+ Adds ID to the list governed by <checkpoint>
+
+config UDEV_EXTRA_edd_id
+ bool "Install udev edd_id callout"
+ default n
+ help
+ edd_id - udev callout to identify BIOS disk drives
+ via EDD
+
+config UDEV_EXTRA_firmware
+ bool "Install firmware support"
+ default n
+ help
+ udev firmware loader via EDD
+
+config UDEV_EXTRA_floppy
+ bool "Install create_floppy_devices callout"
+ default n
+ help
+ create_floppy_devices - udev callout to create all
+ possible floppy devices based on the CMOS type
+
+config UDEV_EXTRA_input_id
+ bool "Install input_id callout"
+ default y
+ help
+ input_id - udev callout to classify input devices
+
+config UDEV_EXTRA_mtd_probe
+ bool "Install mtd_probe callout"
+ default y
+ help
+ mtd_probe - udev callout to probe mtd devices
+
+config UDEV_EXTRA_path_id
+ bool "Install udev path_id callout"
+ default y
+ help
+ path_id - udev callout to create a device path based
+ unique name for a device to implement the Linux
+ Persistent Device Naming scheme
+
+config UDEV_EXTRA_qemu
+ bool "Install qemu specific rules"
+ default y
+ help
+ Install rules for autosuspension of QEMU emulated
+ USB HID devices
+
+config UDEV_EXTRA_rule_generator
+ bool "Install udev rule_generator"
+ default y
+ help
+
+config UDEV_EXTRA_scsi_id
+ bool "Install udev scsi_id callout"
+ default y
+ help
+ scsi_id - retrieve and generate a unique SCSI identifier
+
+config UDEV_EXTRA_usb_id
+ bool "Install udev usb_id callout"
+ default y
+ help
+ usb_id - can find the unique id of USB devices
+
+config UDEV_EXTRA_v4l_id
+ bool "Install udev v4l_id callout"
+ default y
+ help
+ v4l_id - udev callout to identify Video4Linux devices
+
+endmenu
diff --git a/package/system/udev/Makefile b/package/system/udev/Makefile
new file mode 100644
index 0000000..a99533e
--- /dev/null
+++ b/package/system/udev/Makefile
@@ -0,0 +1,157 @@
+#
+# Copyright (C) 2006-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=udev
+PKG_VERSION:=173
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=@KERNEL/linux/utils/kernel/hotplug/
+PKG_MD5SUM:=91a88a359b60bbd074b024883cc0dbde
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+PKG_INSTALL=1
+
+define Package/udev
+ SECTION:=base
+ CATEGORY:=Base system
+ TITLE:=Dynamic device management subsystem
+ URL:=http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
+ MAINTAINER:=Geoff Levand <geoff@infradead.org>
+ MENU:=1
+ DEPENDS:=+librt
+endef
+
+define Package/udev/description
+ udev allows Linux users to have a dynamic /dev directory and it
+ provides the ability to have persistent device names.
+endef
+
+define Package/udev/conffiles
+/etc/udev/udev.conf
+endef
+
+define Package/udev/config
+ source "$(SOURCE)/Config.in"
+endef
+
+udev-args-$(CONFIG_UDEV_DISABLE_LOGGING) += --disable-logging
+udev-args-$(CONFIG_UDEV_ENABLE_DEBUG) += --enable-debug
+udev-args-$(CONFIG_UDEV_EXTRA_edd_id) += --enable-edd
+udev-args-$(CONFIG_UDEV_EXTRA_floppy) += --enable-floppy
+
+# TODO: make hwdb and introspection work
+
+CONFIGURE_ARGS += --prefix=/usr --exec-prefix= --sysconfdir=/etc \
+ --disable-hwdb --disable-keymap --disable-gudev --disable-introspection \
+ --libexecdir=/lib/udev --disable-gtk-doc-html \
+ --sbindir=/sbin $(udev-args-y)
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_accelerometer) += accelerometer
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_accelerometer) += 61-accelerometer.rules
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_ata_id) += ata_id
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_cdrom_id) += cdrom_id
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_cdrom_id) += 60-cdrom_id.rules
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_collect) += collect
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_edd_id) += edd_id
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_edd_id) += 61-persistent-storage-edd.rules
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_firmware) += firmware
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_firmware) += 50-firmware.rules
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_floppy) += create_floppy_devices
+
+# TODO: make gudev work
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_input_id) += input_id
+
+# TODO: make keymap work
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_mtd_probe) += mtd_probe
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_mtd_probe) += 75-probe_mtd.rules
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_path_id) += path_id
+
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_qemu) += 42-qemu-usb.rules
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_rule_generator) += \
+ write_cd_rules write_net_rules
+udev-extra-lib-data-$(CONFIG_UDEV_EXTRA_rule_generator) += \
+ rule_generator.functions
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_rule_generator) += \
+ 75-cd-aliases-generator.rules 75-persistent-net-generator.rules
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_scsi_id) += scsi_id
+
+# TODO: make udev-acl work
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_usb_id) += usb_id
+
+udev-extra-lib-bin-$(CONFIG_UDEV_EXTRA_v4l_id) += v4l_id
+udev-extra-rules-$(CONFIG_UDEV_EXTRA_v4l_id) += 60-persistent-v4l.rules
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(1)/usr/include
+ $(CP) $(PKG_INSTALL_DIR)/usr/include/libudev.h $(1)/usr/include
+ $(INSTALL_DIR) $(1)/usr/share/pkgconfig
+ $(CP) $(PKG_INSTALL_DIR)/usr/share/pkgconfig/udev.pc $(1)/usr/share/pkgconfig
+ $(INSTALL_DIR) $(1)/lib
+ $(CP) $(PKG_INSTALL_DIR)/lib/libudev.so* $(1)/lib
+ $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+ $(CP) $(PKG_INSTALL_DIR)/lib/pkgconfig/libudev.pc $(1)/usr/lib/pkgconfig
+endef
+
+define Package/udev/install
+ $(INSTALL_DIR) $(1)/etc/udev/rules.d
+ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/etc/udev/udev.conf $(1)/etc/udev
+
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) \
+ $(PKG_INSTALL_DIR)/sbin/udevadm \
+ $(PKG_INSTALL_DIR)/sbin/udevd \
+ $(1)/sbin
+
+ $(INSTALL_DIR) $(1)/lib/udev/rules.d
+ $(INSTALL_DATA) \
+ $(addprefix $(PKG_INSTALL_DIR)/lib/udev/rules.d/, \
+ $(udev-extra-rules-y)) \
+ $(addprefix $(PKG_INSTALL_DIR)/lib/udev/rules.d/, \
+ 50-udev-default.rules \
+ 60-persistent-input.rules \
+ 60-persistent-serial.rules \
+ 60-persistent-storage.rules \
+ 80-drivers.rules \
+ 95-udev-late.rules) \
+ $(1)/lib/udev/rules.d
+
+ $(INSTALL_DIR) $(1)/lib
+ $(CP) $(PKG_INSTALL_DIR)/lib/libudev.so* $(1)/lib
+
+ $(INSTALL_DIR) $(1)/lib/udev
+ifneq ($(udev-extra-lib-bin-y),)
+ $(INSTALL_BIN) \
+ $(addprefix $(PKG_INSTALL_DIR)/lib/udev/, \
+ $(udev-extra-lib-bin-y)) \
+ $(1)/lib/udev/
+endif
+ifneq ($(udev-extra-lib-data-y),)
+ $(INSTALL_DATA) \
+ $(addprefix $(PKG_INSTALL_DIR)/lib/udev/, \
+ $(udev-extra-lib-data-y)) \
+ $(1)/lib/udev/
+endif
+endef
+
+$(eval $(call BuildPackage,udev))
diff --git a/package/system/udev/patches/0001-build-don-t-use-gc-sections.patch b/package/system/udev/patches/0001-build-don-t-use-gc-sections.patch
new file mode 100644
index 0000000..f01a5ae
--- /dev/null
+++ b/package/system/udev/patches/0001-build-don-t-use-gc-sections.patch
@@ -0,0 +1,31 @@
+From 971a09345f108189ed899b236784a5440e43c8b6 Mon Sep 17 00:00:00 2001
+From: Daniel Mierswa <impulze@impulze.org>
+Date: Sun, 31 Jul 2011 23:51:49 +0000
+Subject: [PATCH 1/2] build: don't use --gc-sections
+
+somehow won't work with the wrt toolchain
+---
+ Makefile.am | 5 +----
+ 1 files changed, 1 insertions(+), 4 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index a0c007a..3d8ce92 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -18,12 +18,9 @@ AM_CPPFLAGS = \
+ -DLIBEXECDIR=\""$(libexecdir)"\"
+
+ AM_CFLAGS = \
+- -fvisibility=hidden \
+- -ffunction-sections \
+- -fdata-sections
++ -fvisibility=hidden
+
+ AM_LDFLAGS = \
+- -Wl,--gc-sections \
+ -Wl,--as-needed
+
+ DISTCHECK_CONFIGURE_FLAGS = \
+--
+1.7.6
+
diff --git a/package/system/udev/patches/0002-udevd-add-lrt-for-message-queue-symbols.patch b/package/system/udev/patches/0002-udevd-add-lrt-for-message-queue-symbols.patch
new file mode 100644
index 0000000..55466bc
--- /dev/null
+++ b/package/system/udev/patches/0002-udevd-add-lrt-for-message-queue-symbols.patch
@@ -0,0 +1,25 @@
+From ae90737100d901723af9890e69798bd1dac9a86d Mon Sep 17 00:00:00 2001
+From: Daniel Mierswa <impulze@impulze.org>
+Date: Sun, 31 Jul 2011 23:53:21 +0000
+Subject: [PATCH 2/2] udevd: add -lrt for message queue symbols
+
+---
+ Makefile.am | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 3d8ce92..7d8a4b6 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -164,7 +164,7 @@ udev_udevd_SOURCES = \
+ udev/udevd.c \
+ udev/sd-daemon.h \
+ udev/sd-daemon.c
+-udev_udevd_LDADD = libudev/libudev-private.la
++udev_udevd_LDADD = libudev/libudev-private.la -lrt
+
+ udev_udevadm_SOURCES = \
+ $(udev_common_sources) \
+--
+1.7.6
+
diff --git a/package/system/udev/patches/0003-add_btn_trigger_happy_define.patch b/package/system/udev/patches/0003-add_btn_trigger_happy_define.patch
new file mode 100644
index 0000000..77eaf13
--- /dev/null
+++ b/package/system/udev/patches/0003-add_btn_trigger_happy_define.patch
@@ -0,0 +1,13 @@
+--- a/extras/input_id/input_id.c
++++ b/extras/input_id/input_id.c
+@@ -30,6 +30,10 @@
+ #include "libudev.h"
+ #include "libudev-private.h"
+
++#ifndef BTN_TRIGGER_HAPPY
++#define BTN_TRIGGER_HAPPY 0x2c0
++#endif
++
+ /* we must use this kernel-compatible implementation */
+ #define BITS_PER_LONG (sizeof(unsigned long) * 8)
+ #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
diff --git a/package/system/usign/Makefile b/package/system/usign/Makefile
new file mode 100644
index 0000000..713bb93
--- /dev/null
+++ b/package/system/usign/Makefile
@@ -0,0 +1,43 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=usign
+PKG_VERSION:=2015-05-08
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://git.openwrt.org/project/usign.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=cf8dcdb8a4e874c77f3e9a8e9b643e8c17b19131
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+CMAKE_INSTALL:=1
+PKG_CHECK_FORMAT_SECURITY:=1
+PKG_USE_MIPS16:=0
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/usign
+ SECTION:=base
+ CATEGORY:=Base system
+ DEPENDS:=+libubox
+ TITLE:=OpenWrt signature verification utility
+endef
+
+CMAKE_OPTIONS += \
+ -DUSE_LIBUBOX=on
+
+define Package/usign/install
+ $(INSTALL_DIR) $(1)/usr/bin
+
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/usign $(1)/usr/bin
+ ln -s usign $(1)/usr/bin/signify
+endef
+
+$(eval $(call BuildPackage,usign))
+$(eval $(call HostBuild))
diff --git a/package/system/zram-swap/Makefile b/package/system/zram-swap/Makefile
new file mode 100644
index 0000000..bd84d79
--- /dev/null
+++ b/package/system/zram-swap/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=zram-swap
+PKG_VERSION:=1
+PKG_RELEASE:=2
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/zram-swap
+ SECTION:=utils
+ CATEGORY:=Base system
+ DEPENDS:=+kmod-zram +!BUSYBOX_CONFIG_MKSWAP:swap-utils +!BUSYBOX_CONFIG_SWAPONOFF:block-mount
+ TITLE:=ZRAM swap scripts
+ PKGARCH:=all
+endef
+
+define Package/zram-swap/description
+ A script to activate swaping on a compressed zram partition. This
+ could be used to increase the available memory, by using compressed
+ memory.
+endef
+
+define Build/Prepare
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/zram-swap/install
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/zram.init $(1)/etc/init.d/zram
+endef
+
+$(eval $(call BuildPackage,zram-swap))
diff --git a/package/system/zram-swap/files/zram.init b/package/system/zram-swap/files/zram.init
new file mode 100644
index 0000000..23de915
--- /dev/null
+++ b/package/system/zram-swap/files/zram.init
@@ -0,0 +1,123 @@
+#!/bin/sh /etc/rc.common
+
+START=15
+
+ram_size()
+{
+ local line
+
+ while read line; do case "$line" in MemTotal:*) set $line; echo "$2"; break ;; esac; done </proc/meminfo
+}
+
+zram_size() # in megabytes
+{
+ local zram_size="$( uci -q get system.@system[0].zram_size_mb )"
+ local ram_size="$( ram_size )"
+
+ if [ -z "$zram_size" ]; then
+ # e.g. 6mb for 16mb-routers or 61mb for 128mb-routers
+ echo $(( $ram_size / 2048 ))
+ else
+ echo "$zram_size"
+ fi
+}
+
+zram_applicable()
+{
+ local zram_dev="$1"
+
+ grep -sq ^"$zram_dev " /proc/swaps && {
+ logger -s -t zram_applicable -p daemon.notice "[OK] '$zram_dev' already active"
+ return 1
+ }
+
+ [ -e "$zram_dev" ] || {
+ logger -s -t zram_applicable -p daemon.crit "[ERROR] device '$zram_dev' not found"
+ return 1
+ }
+
+ which mkswap >/dev/null || {
+ logger -s -t zram_applicable -p daemon.err "[ERROR] 'mkswap' not installed"
+ return 1
+ }
+
+ which swapon >/dev/null || {
+ logger -s -t zram_applicable -p daemon.err "[ERROR] 'swapon' not installed"
+ return 1
+ }
+
+ which swapoff >/dev/null || {
+ logger -s -t zram_applicable -p daemon.err "[ERROR] 'swapoff' not installed"
+ return 1
+ }
+}
+
+zram_dev()
+{
+ local core="$1"
+
+ echo "/dev/zram${core:-0}"
+}
+
+zram_reset()
+{
+ local dev="$1"
+ local message="$2"
+ local proc_entry="/sys/block/$( basename "$dev" )/reset"
+
+ logger -s -t zram_reset -p daemon.debug "$message via $proc_entry"
+ echo "1" >"$proc_entry"
+}
+
+list_cpu_idx()
+{
+ local line i=0
+
+ while read line; do {
+ case "$line" in
+ [Pp]rocessor*)
+ echo $i
+ i=$(( $i + 1 ))
+ ;;
+ esac
+ } done <"/proc/cpuinfo"
+}
+
+start()
+{
+ # http://shmilyxbq-compcache.googlecode.com/hg/README
+ # if >1 cpu_core, reinit kmodule with e.g. num_devices=4
+
+ local zram_size="$( zram_size )"
+ local zram_dev core
+
+ for core in $( list_cpu_idx ); do {
+ zram_dev="$( zram_dev "$core" )"
+ zram_applicable "$zram_dev" || return 1
+
+ logger -s -t zram_start -p daemon.debug "activating '$zram_dev' for swapping ($zram_size MegaBytes)"
+
+ zram_reset "$zram_dev" "enforcing defaults"
+ echo $(( $zram_size * 1024 * 1024 )) >"/sys/block/$( basename $zram_dev )/disksize"
+ mkswap "$zram_dev"
+ swapon "$zram_dev"
+ } done
+}
+
+stop()
+{
+ local zram_dev proc_entry
+
+ for core in $( list_cpu_idx ); do {
+ zram_dev="$( zram_dev "$core" )"
+ proc_entry="/sys/block/$( basename "$zram_dev" )/reset"
+
+ grep -sq ^"$zram_dev " /proc/swaps && {
+ logger -s -t zram_stop -p daemon.debug "deactivate swap $zram_dev"
+ swapoff "$zram_dev"
+ }
+
+ zram_reset "$zram_dev" "claiming memory back"
+ } done
+}
+