diff --git a/luci-app-store/Makefile b/luci-app-store/Makefile index 690593a9c..034f5aa6e 100644 --- a/luci-app-store/Makefile +++ b/luci-app-store/Makefile @@ -11,13 +11,13 @@ LUCI_DEPENDS:=+curl +opkg +luci-base +tar +libuci-lua +mount-utils +luci-lib-tas LUCI_EXTRA_DEPENDS:=luci-lib-taskd (>=1.0.19) LUCI_PKGARCH:=all -PKG_VERSION:=0.1.27-4 +PKG_VERSION:=0.1.28-2 # PKG_RELEASE MUST be empty for luci.mk PKG_RELEASE:= -ISTORE_UI_VERSION:=0.1.27 -ISTORE_UI_RELEASE:=2 -PKG_HASH:=7fb8e9983dd33b14c43de3caf6a6121df0727e0adac6c666354e0d8a0cffa0b8 +ISTORE_UI_VERSION:=0.1.28 +ISTORE_UI_RELEASE:=1 +PKG_HASH:=c45d7552a4c52fdd2f5a2a9bbc94d14a66c5af187ef8a117a3e08b6a9a4b7dbf PKG_SOURCE_URL_FILE:=v$(ISTORE_UI_VERSION)-$(ISTORE_UI_RELEASE).tar.gz PKG_SOURCE:=istore-ui-$(PKG_SOURCE_URL_FILE) diff --git a/luci-app-store/luasrc/controller/store.lua b/luci-app-store/luasrc/controller/store.lua index cbde2eafb..7a876288e 100644 --- a/luci-app-store/luasrc/controller/store.lua +++ b/luci-app-store/luasrc/controller/store.lua @@ -2,6 +2,7 @@ module("luci.controller.store", package.seeall) local myopkg = "is-opkg" local is_backup = "/usr/libexec/istore/backup" +local is_overlay_backup = "/usr/libexec/istore/overlay-backup" local page_index = {"admin", "store", "pages"} function index() @@ -44,16 +45,18 @@ function index() store_api(action, false) end - -- backup + -- istore backup if nixio.fs.access("/usr/libexec/istore/backup") then entry({"admin", "store", "get_support_backup_features"}, call("get_support_backup_features")) entry({"admin", "store", "light_backup"}, post("light_backup")) entry({"admin", "store", "get_light_backup_file"}, call("get_light_backup_file")) - entry({"admin", "store", "local_backup"}, post("local_backup")) entry({"admin", "store", "light_restore"}, post("light_restore")) - entry({"admin", "store", "local_restore"}, post("local_restore")) entry({"admin", "store", "get_backup_app_list_file_path"}, call("get_backup_app_list_file_path")) entry({"admin", "store", "get_backup_app_list"}, call("get_backup_app_list")) + end + if nixio.fs.access("/usr/libexec/istore/backup") or nixio.fs.access("/usr/libexec/istore/overlay-backup") then + entry({"admin", "store", "local_backup"}, post("local_backup")) + entry({"admin", "store", "local_restore"}, post("local_restore")) entry({"admin", "store", "get_available_backup_file_list"}, call("get_available_backup_file_list")) entry({"admin", "store", "set_local_backup_dir_path"}, post("set_local_backup_dir_path")) entry({"admin", "store", "get_local_backup_dir_path"}, call("get_local_backup_dir_path")) @@ -160,6 +163,9 @@ function store_index() if fs.access("/usr/libexec/istore/backup") then features[#features+1] = "backup" end + if luci.sys.call(is_overlay_backup .. " supports_overlay_backup >/dev/null 2>&1") == 0 then + features[#features+1] = "overlay" + end if luci.sys.call("which docker >/dev/null 2>&1") == 0 then features[#features+1] = "docker" end @@ -682,18 +688,27 @@ function local_backup() local code, out, err, ret local error_ret local path = luci.http.formvalue("path") + local type = luci.http.formvalue("type") or "istore" if path ~= "" then -- judge path + local fs = require "nixio.fs" + fs.mkdirr(path) code,out,err = is_exec("findmnt -T " .. path .. " -o TARGET|sed -n 2p") - if out:gsub("[\r\n]", "") == "/" or out:gsub("[\r\n]", "") == "/tmp" then + local mp = out:gsub("[\r\n]", "") + if mp == "/" or mp == "/tmp" then -- error error_ret = {code = 500, stderr = "Path Error,Can not be / or tmp."} luci.http.prepare_content("application/json") - luci.http.write_json(error_ret) + luci.http.write_json(error_ret) + elseif type == "overlay" and ( mp == "/overlay" or mp == "/ext_overlay" ) then + -- error + error_ret = {code = 500, stderr = "Path Error,Can not be /overlay or /ext_overlay."} + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) else -- update local backup path update_local_backup_path(path) - code,out,err = _action(is_backup, "backup", path) + code,out,err = _action(type == "overlay" and is_overlay_backup or is_backup, "backup", path) ret = { code = code, stdout = out, @@ -761,9 +776,10 @@ end -- post local_restore function local_restore() local path = luci.http.formvalue("path") + local type = luci.http.formvalue("type") or "istore" local code, out, err, ret if path ~= "" then - code,out,err = _action(is_backup, "restore", path) + code,out,err = _action(type == "overlay" and is_overlay_backup or is_backup, "restore", path) ret = { code = code, stdout = out, @@ -821,12 +837,13 @@ function get_available_backup_file_list() local error_ret = {code = 500, msg = "Unknown"} local success_ret = {code = 200,msg = "Unknown"} local path = luci.http.formvalue("path") + local type = luci.http.formvalue("type") or "istore" local r,o,e if path ~= "" then -- update local backup path update_local_backup_path(path) - r,o,e = is_exec(is_backup .. " get_available_backup_file_list " .. luci.util.shellquote(path)) + r,o,e = is_exec((type == "overlay" and is_overlay_backup or is_backup) .. " get_available_backup_file_list " .. luci.util.shellquote(path)) if r ~= 0 then error_ret.msg = e luci.http.prepare_content("application/json") diff --git a/luci-app-store/root/usr/libexec/istore/backup b/luci-app-store/root/usr/libexec/istore/backup index c1b506b97..8c2b77d8e 100755 --- a/luci-app-store/root/usr/libexec/istore/backup +++ b/luci-app-store/root/usr/libexec/istore/backup @@ -170,7 +170,7 @@ backup() { ipk_build ${pkg_name} $BACKUP_PATH/backup_istore_$date done - # 5. create tar.gz file,and remove fir + # 5. create tar.gz file,and remove dir cd $BACKUP_PATH echo "write backup file to $BACKUP_PATH/backup_istore_$date.backup.tar.gz" tar -czf $BACKUP_PATH/backup_istore_$date.backup.tar.gz backup_istore_$date @@ -246,10 +246,10 @@ get_backup_app_list() { } get_available_backup_file_list() { + local backup_file if [ -n "$1" ]; then - for backup_file in `ls $1/*.backup.tar.gz`; do - filename=${backup_file##*/} - echo "${filename}" + for backup_file in `cd $1 && ls backup_istore_*.backup.tar.gz`; do + echo "${backup_file}" done else echo "input backup path is null" diff --git a/luci-app-store/root/usr/libexec/istore/overlay-backup b/luci-app-store/root/usr/libexec/istore/overlay-backup new file mode 100755 index 000000000..318b81f9d --- /dev/null +++ b/luci-app-store/root/usr/libexec/istore/overlay-backup @@ -0,0 +1,177 @@ +#!/bin/sh + +TMP_SELF_COPY=/var/run/cloned-overlay-backup + +action=${1} +shift + +has_overlay() { + [ -d "/overlay/upper" ] || return 1 + [ "overlay" = "$(/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }')" ] || return 1 + + return 0 +} + +has_ext_overlay() { + [ -d "/ext_overlay/upper" ] || return 1 + grep '^overlayfs:/overlay / ' /proc/mounts | grep -Fq 'upperdir=/ext_overlay/upper' || return 1 + + return 0 +} + +backup() { + if ! has_overlay; then + echo "only supports squashfs firmware" + exit 1 + fi + if [ -z "$1" ]; then + echo "input backup path is null" + exit 1 + fi + local BACKUP_PATH="$1" + + if echo "$BACKUP_PATH" | grep -q -e '^/overlay/upper' -e '^/ext_overlay/upper' ; then + echo "can not backup to /overlay/upper, /ext_overlay/upper" + exit 1 + fi + + if [ ! -d "${BACKUP_PATH}" ] && ! mkdir -p "${BACKUP_PATH}" ; then + echo "backup path does not exist and can not be create" + exit 1 + fi + + local realpath="$(cd "${BACKUP_PATH}"; pwd -P)" + if [ -z "$realpath" ]; then + echo "cannot get absolute path of ${BACKUP_PATH}" + exit 1 + fi + + local mountpoint=$(findmnt -T $realpath -o TARGET | sed -n 2p) + # while read -r; do + # if [[ "x$realpath" == "x$REPLY" || "x${realpath#$REPLY/}" != "x$realpath" ]]; then + # mountpoint="$REPLY" + # break + # fi + # done < <( + # cat /proc/mounts | grep -v '^overlay ' | awk 'NR>1 {print $2}' | grep -v '^/$' | \ + # sort -u | \ + # while read -r; do printf "%b\n" "$REPLY" ; done | \ + # awk '{print length, $0}' | sort -nr | cut -d' ' -f2- + # ) + + if [ "/" = "$mountpoint" ]; then + echo "can not backup to /" + exit 1 + else + echo "found mount point $mountpoint" + fi + + local tar_extra_args= + if has_ext_overlay; then + tar_extra_args="$tar_extra_args ext_overlay/upper" + fi + + local hostname=$(cat /proc/sys/kernel/hostname) + local fwver=$(. /etc/openwrt_release; echo $DISTRIB_ID-$DISTRIB_RELEASE) + + local date=$(date +%Y-%m%d-%H%M) + local backup_name="backup_overlay_${hostname}_${fwver}_${date}.overlay.tar.gz" + local backup_full_path="$BACKUP_PATH/$backup_name" + echo "writing backup to $backup_full_path" + if tar -C / -cz overlay/upper $tar_extra_args > "$backup_full_path" ; then + sync "$BACKUP_PATH" + echo "backup success" + return 0 + else + rm -f "$backup_full_path" + echo "backup failed" + exit 1 + fi +} + +restore() { + if ! has_overlay; then + echo "only supports squashfs firmware" + exit 1 + fi + if [ -z "$1" ]; then + echo "input backup path is null" + exit 1 + fi + local BACKUP_PATH_FILE="$1" + + if [ ! -f "${BACKUP_PATH_FILE}" ]; then + echo "invalid backup file, can not restore" + exit 1 + fi + + local tar_extra_args= + if has_ext_overlay; then + tar_extra_args="$tar_extra_args ext_overlay/upper" + fi + + sync / + echo "restoring from ${BACKUP_PATH_FILE}" + if tar -C / -xz overlay/upper $tar_extra_args < "${BACKUP_PATH_FILE}" ; then + sync /overlay /ext_overlay + echo "restore success" + echo "schedule to restart after 5 seconds!" + /etc/init.d/tasks task_add reboot 'reboot -d 5' + return 0 + else + echo "restore failed" + exit 1 + fi +} + +supports_overlay_backup() { + has_overlay || return 1 + echo "overlay" + has_ext_overlay && echo "ext_overlay" + return 0 +} + +get_backup_file_list() { + local backup_file + if [ -n "$1" ]; then + for backup_file in `cd $1 && ls backup_overlay_*.overlay.tar.gz`; do + echo "${backup_file}" + done + else + echo "input backup path is null" + exit 1 + fi +} + +usage() { + echo "usage: overlay-backup sub-command [arguments...]" + echo "where sub-command is one of:" + echo " backup [dir] Backup all installed package(s) to [directory]" + echo " restore [dir] Restore package(s) by [directory]" + echo " supports_overlay_backup check system supports overlay backup" + echo " get_backup_file_list [dir] get local available backup file list in [dir]" +} + +case $action in + "supports_overlay_backup") + supports_overlay_backup + ;; + "backup") + backup "$@" + ;; + "restore") + if [ "$0" = "$TMP_SELF_COPY" ]; then + restore "$@" + else + echo "copy self $0 to $TMP_SELF_COPY when restore" + cp -af "$0" "$TMP_SELF_COPY" + exec "$TMP_SELF_COPY" restore "$@" + fi + ;; + "get_available_backup_file_list") + get_backup_file_list "$@" + ;; + *) + usage + ;; +esac