From 3300cccf506a9f251c12afbe95e9efe2cdec7f2a Mon Sep 17 00:00:00 2001 From: YGAS Date: Thu, 3 Mar 2022 14:38:35 +0800 Subject: [PATCH] update store --- applications/luci-app-store/Makefile | 8 +- .../luasrc/controller/store.lua | 335 +++++++++++++++++ .../luci-app-store/root/bin/ipkg-build | 200 ++++++++++ applications/luci-app-store/root/bin/is-opkg | 341 +++++++++++++++++- .../root/usr/share/opkg/intercept/rm | 7 + 5 files changed, 871 insertions(+), 20 deletions(-) create mode 100755 applications/luci-app-store/root/bin/ipkg-build create mode 100755 applications/luci-app-store/root/usr/share/opkg/intercept/rm diff --git a/applications/luci-app-store/Makefile b/applications/luci-app-store/Makefile index c240302..71e0115 100755 --- a/applications/luci-app-store/Makefile +++ b/applications/luci-app-store/Makefile @@ -7,19 +7,19 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI based ipk store LUCI_DESCRIPTION:=luci-app-store is a ipk store developed by LinkEase team -LUCI_DEPENDS:=+curl +opkg +luci-lib-ipkg +LUCI_DEPENDS:=+tar +coreutils +coreutils-stat +luci-lib-ipkg +curl +opkg +libuci-lua +mount-utils LUCI_PKGARCH:=all PKG_VERSION:=0.1.7 -PKG_RELEASE:=2 +PKG_RELEASE:=1 ISTORE_UI_VERSION:=1.0 -ISTORE_UI_RELEASE:=7 +ISTORE_UI_RELEASE:=8 PKG_HASH:=395936ef07403674068a7719c9fcbad59dafa0f2b39d6da05d9eae0b5a7050a6 PKG_SOURCE_URL_FILE:=v$(ISTORE_UI_VERSION)-$(ISTORE_UI_RELEASE).tar.gz PKG_SOURCE:=istore-ui-$(PKG_SOURCE_URL_FILE) -PKG_SOURCE_URL:=https://github.com/linkease/istore-ui/archive/refs/tags +PKG_SOURCE_URL:=https://github.com/YGAS/istore-ui/archive/refs/tags PKG_MAINTAINER:=jjm2473 diff --git a/applications/luci-app-store/luasrc/controller/store.lua b/applications/luci-app-store/luasrc/controller/store.lua index a3c52ca..c4a37ec 100755 --- a/applications/luci-app-store/luasrc/controller/store.lua +++ b/applications/luci-app-store/luasrc/controller/store.lua @@ -23,6 +23,19 @@ function index() entry({"admin", "store", "upload"}, post("store_upload")) entry({"admin", "store", "check_self_upgrade"}, call("check_self_upgrade")) entry({"admin", "store", "do_self_upgrade"}, post("do_self_upgrade")) + + 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")) + 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")) + for _, action in ipairs({"update", "install", "upgrade", "remove"}) do store_api(action, true) end @@ -289,3 +302,325 @@ function store_upload() luci.http.prepare_content("application/json") luci.http.write_json(ret) end + +local function split(str,reps) + local resultStrList = {} + string.gsub(str,'[^'..reps..']+',function (w) + table.insert(resultStrList,w) + end) + return resultStrList +end + +local function ltn12_popen(command) + + local fdi, fdo = nixio.pipe() + local pid = nixio.fork() + + if pid > 0 then + fdo:close() + local close + return function() + local buffer = fdi:read(2048) + local wpid, stat = nixio.waitpid(pid, "nohang") + if not close and wpid and stat == "exited" then + close = true + end + + if buffer and #buffer > 0 then + return buffer + elseif close then + fdi:close() + return nil + end + end + elseif pid == 0 then + nixio.dup(fdo, nixio.stdout) + fdi:close() + fdo:close() + nixio.exec("/bin/sh", "-c", command) + end +end + +-- call get_support_backup_features +function get_support_backup_features() + local jsonc = require "luci.jsonc" + local error_ret = {code = 500, msg = "Unknown"} + local success_ret = {code = 200,msg = "Unknown"} + local r,o,e = is_exec(myopkg .. " get_support_backup_features") + if r ~= 0 then + error_ret.msg = e + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + else + success_ret.code = 200 + success_ret.msg = jsonc.stringify(split(o,'\n')) + luci.http.prepare_content("application/json") + luci.http.write_json(success_ret) + end +end + +-- post light_backup +function light_backup() + local jsonc = require "luci.jsonc" + local error_ret = {code = 500, msg = "Unknown"} + local success_ret = {code = 200,msg = "Unknown"} + local r,o,e = is_exec(myopkg .. " backup") + + if r ~= 0 then + error_ret.msg = e + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + else + success_ret.code = 200 + success_ret.msg = o:gsub("[\r\n]", "") + luci.http.prepare_content("application/json") + luci.http.write_json(success_ret) + end +end + +-- call get_light_backup_file +function get_light_backup_file() + local light_backup_cmd = "tar -c %s | gzip 2>/dev/null" + local loght_backup_filelist = "/etc/istore/app.list" + local reader = ltn12_popen(light_backup_cmd:format(loght_backup_filelist)) + luci.http.header('Content-Disposition', 'attachment; filename="light-backup-%s-%s.tar.gz"' % { + luci.sys.hostname(), os.date("%Y-%m-%d")}) + luci.http.prepare_content("application/x-targz") + luci.ltn12.pump.all(reader, luci.http.write) +end + +local function update_local_backup_path(path) + local uci = require "uci" + local fs = require "nixio.fs" + local x = uci.cursor() + local local_backup_path + + if fs.access("/etc/config/istore") then + local_backup_path = x:get("istore","istore","local_backup_path") + else + --create config file + local f=io.open("/etc/config/istore","a+") + f:write("config istore \'istore\'\n\toption local_backup_path \'\'") + f:flush() + f:close() + end + + if path ~= local_backup_path then + -- set uci config + x:set("istore","istore","local_backup_path",path) + x:commit("istore") + end +end + +-- post local_backup +function local_backup() + local code, out, err, ret + local error_ret + local path = luci.http.formvalue("path") + if path ~= "" then + -- judge 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 + -- error + error_ret = {code = 500, msg = "Path Error,Can not be / or tmp."} + 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 = is_exec(myopkg .. " backup " .. path) + ret = { + code = code, + stdout = out, + stderr = err + } + luci.http.prepare_content("application/json") + luci.http.write_json(ret) + end + else + -- error + error_ret = {code = 500, msg = "Path Unknown"} + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + end +end + +-- post light_restore +function light_restore() + local fd + local path + local finished = false + local tmpdir = "/tmp/" + luci.http.setfilehandler( + function(meta, chunk, eof) + if not fd then + path = tmpdir .. "/" .. meta.file + fd = io.open(path, "w") + end + if chunk then + fd:write(chunk) + end + if eof then + fd:close() + finished = true + end + end + ) + + local code, out, err, ret + + if finished then + is_exec("rm /etc/istore/app.list;tar -xzf " .. path .. " -C /") + if nixio.fs.access("/etc/istore/app.list") then + code,out,err = is_exec(myopkg .. " restore") + ret = { + code = code, + stdout = out, + stderr = err + } + luci.http.prepare_content("application/json") + luci.http.write_json(ret) + else + local error_ret = {code = 500, msg = "File is error!"} + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + end + -- remove file + is_exec("rm " .. path) + else + ret = {code = 500, msg = "upload failed!"} + luci.http.prepare_content("application/json") + luci.http.write_json(ret) + end +end + +-- post local_restore +function local_restore() + local path = luci.http.formvalue("path") + local code, out, err, ret + if path ~= "" then + code,out,err = is_exec(myopkg .. " restore " .. path) + ret = { + code = code, + stdout = out, + stderr = err + } + luci.http.prepare_content("application/json") + luci.http.write_json(ret) + else + -- error + error_ret = {code = 500, msg = "Path Unknown"} + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + end +end + +-- call get_backup_app_list_file_path +function get_backup_app_list_file_path() + local jsonc = require "luci.jsonc" + local error_ret = {code = 500, msg = "Unknown"} + local success_ret = {code = 200,msg = "Unknown"} + local r,o,e = is_exec(myopkg .. " get_backup_app_list_file_path") + if r ~= 0 then + error_ret.msg = e + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + else + success_ret.code = 200 + success_ret.msg = o:gsub("[\r\n]", "") + luci.http.prepare_content("application/json") + luci.http.write_json(success_ret) + end +end + +-- call get_backup_app_list +function get_backup_app_list() + local jsonc = require "luci.jsonc" + local error_ret = {code = 500, msg = "Unknown"} + local success_ret = {code = 200,msg = "Unknown"} + local r,o,e = is_exec(myopkg .. " get_backup_app_list") + if r ~= 0 then + error_ret.msg = e + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + else + success_ret.code = 200 + success_ret.msg = jsonc.stringify(split(o,'\n')) + luci.http.prepare_content("application/json") + luci.http.write_json(success_ret) + end +end + +-- call get_available_backup_file_list +function get_available_backup_file_list() + local jsonc = require "luci.jsonc" + local error_ret = {code = 500, msg = "Unknown"} + local success_ret = {code = 200,msg = "Unknown"} + local path = luci.http.formvalue("path") + local r,o,e + + if path ~= "" then + -- update local backup path + update_local_backup_path(path) + r,o,e = is_exec(myopkg .. " get_available_backup_file_list " .. path) + if r ~= 0 then + error_ret.msg = e + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + else + success_ret.code = 200 + success_ret.msg = jsonc.stringify(split(o,'\n')) + luci.http.prepare_content("application/json") + luci.http.write_json(success_ret) + end + else + -- set error code + error_ret.msg = "Path Unknown" + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + end +end + +-- post set_local_backup_dir_path +function set_local_backup_dir_path() + local path = luci.http.formvalue("path") + local success_ret = {code = 200,msg = "Success"} + local error_ret = {code = 500, msg = "Unknown"} + + if path ~= "" then + -- update local backup path + update_local_backup_path(path) + luci.http.prepare_content("application/json") + luci.http.write_json(success_ret) + else + -- set error code + error_ret.msg = "Path Unknown" + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + end +end + +-- call get_local_backup_dir_path +function get_local_backup_dir_path() + local uci = require "uci" + local fs = require "nixio.fs" + local x = uci.cursor() + local local_backup_path = nil + local success_ret = {code = 200,msg = "Unknown"} + local error_ret = {code = 500, msg = "Path Unknown"} + + if fs.access("/etc/config/istore") then + local_backup_path = x:get("istore","istore","local_backup_path") + if local_backup_path == nil then + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + else + success_ret.msg = local_backup_path:gsub("[\r\n]", "") + luci.http.prepare_content("application/json") + luci.http.write_json(success_ret) + end + else + luci.http.prepare_content("application/json") + luci.http.write_json(error_ret) + end +end \ No newline at end of file diff --git a/applications/luci-app-store/root/bin/ipkg-build b/applications/luci-app-store/root/bin/ipkg-build new file mode 100755 index 0000000..343aab6 --- /dev/null +++ b/applications/luci-app-store/root/bin/ipkg-build @@ -0,0 +1,200 @@ +#!/bin/sh + +# ipkg-build -- construct a .ipk from a directory +# Carl Worth +# based on a script by Steve Redler IV, steve@sr-tech.com 5-21-2001 +# 2003-04-25 rea@sr.unh.edu +# Updated to work on Familiar Pre0.7rc1, with busybox tar. +# Note it Requires: binutils-ar (since the busybox ar can't create) +# For UID debugging it needs a better "find". +set -e + +version=1.0 +FIND="$(command -v find)" +FIND="${FIND:-$(command -v gfind)}" +TAR="${TAR:-$(command -v tar)}" +GZIP="$(command -v gzip)" + +# try to use fixed source epoch +if [ -n "$PKG_SOURCE_DATE_EPOCH" ]; then + TIMESTAMP=$(date --date="@$PKG_SOURCE_DATE_EPOCH") +elif [ -n "$SOURCE_DATE_EPOCH" ]; then + TIMESTAMP=$(date --date="@$SOURCE_DATE_EPOCH") +else + TIMESTAMP=$(date) +fi + +ipkg_extract_value() { + sed -e "s/^[^:]*:[[:space:]]*//" +} + +required_field() { + field=$1 + + grep "^$field:" < $CONTROL/control | ipkg_extract_value +} + +pkg_appears_sane() { + local pkg_dir=$1 + + local owd=$PWD + cd $pkg_dir + + PKG_ERROR=0 + pkg=`required_field Package` + version=`required_field Version | sed 's/Version://; s/^.://g;'` + arch=`required_field Architecture` + + if echo $pkg | grep '[^a-zA-Z0-9_.+-]'; then + echo "*** Error: Package name $name contains illegal characters, (other than [a-z0-9.+-])" >&2 + PKG_ERROR=1; + fi + + if [ -f $CONTROL/conffiles ]; then + rm -f $CONTROL/conffiles.resolved + + for cf in `$FIND $(sed -e "s!^/!$pkg_dir/!" $CONTROL/conffiles) -type f`; do + echo "${cf#$pkg_dir}" >> $CONTROL/conffiles.resolved + done + + rm $CONTROL/conffiles + if [ -f $CONTROL/conffiles.resolved ]; then + mv $CONTROL/conffiles.resolved $CONTROL/conffiles + chmod 0644 $CONTROL/conffiles + fi + fi + + cd $owd + return $PKG_ERROR +} + +resolve_file_mode_id() { + local var=$1 type=$2 name=$3 id + + case "$name" in + root) + id=0 + ;; + *[!0-9]*) + id=$(sed -ne "s#^$type $name \\([0-9]\\+\\)\\b.*\$#\\1#p" "$TOPDIR/tmp/.packageusergroup" 2>/dev/null) + ;; + *) + id=$name + ;; + esac + + export "$var=$id" + + [ -n "$id" ] +} + +### +# ipkg-build "main" +### +file_modes="" +usage="Usage: $0 [-v] [-h] [-m] []" +while getopts "hvm:" opt; do + case $opt in + v ) echo $version + exit 0 + ;; + h ) echo $usage >&2 ;; + m ) file_modes=$OPTARG ;; + \? ) echo $usage >&2 + esac +done + + +shift $(($OPTIND - 1)) + +# continue on to process additional arguments + +case $# in +1) + dest_dir=$PWD + ;; +2) + dest_dir=$2 + if [ "$dest_dir" = "." -o "$dest_dir" = "./" ] ; then + dest_dir=$PWD + fi + ;; +*) + echo $usage >&2 + exit 1 + ;; +esac + +pkg_dir=$1 + +if [ ! -d $pkg_dir ]; then + echo "*** Error: Directory $pkg_dir does not exist" >&2 + exit 1 +fi + +# CONTROL is second so that it takes precedence +CONTROL= +[ -d $pkg_dir/CONTROL ] && CONTROL=CONTROL +if [ -z "$CONTROL" ]; then + echo "*** Error: Directory $pkg_dir has no CONTROL subdirectory." >&2 + exit 1 +fi + +if ! pkg_appears_sane $pkg_dir; then + echo >&2 + echo "ipkg-build: Please fix the above errors and try again." >&2 + exit 1 +fi + +tmp_dir=$dest_dir/IPKG_BUILD.$$ +mkdir $tmp_dir + +echo $CONTROL > $tmp_dir/tarX +cd $pkg_dir +for file_mode in $file_modes; do + case $file_mode in + /*:*:*:*) + ;; + *) + echo "ERROR: file modes must use absolute path and contain user:group:mode" + echo "$file_mode" + exit 1 + ;; + esac + + mode=${file_mode##*:}; path=${file_mode%:*} + group=${path##*:}; path=${path%:*} + user=${path##*:}; path=${path%:*} + + if ! resolve_file_mode_id uid user "$user"; then + echo "ERROR: unable to resolve uid of $user" >&2 + exit 1 + fi + + if ! resolve_file_mode_id gid group "$group"; then + echo "ERROR: unable to resolve gid of $group" >&2 + exit 1 + fi + + chown "$uid:$gid" "$pkg_dir/$path" + chmod "$mode" "$pkg_dir/$path" +done +$TAR -X $tmp_dir/tarX --format=gnu --sort=name -cpf - --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/data.tar.gz + +installed_size=`stat -c "%s" $tmp_dir/data.tar.gz` +sed -i -e "s/^Installed-Size: .*/Installed-Size: $installed_size/" \ + $pkg_dir/$CONTROL/control + +( cd $pkg_dir/$CONTROL && $TAR --format=gnu --sort=name -cf - --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/control.tar.gz ) +rm $tmp_dir/tarX + +echo "2.0" > $tmp_dir/debian-binary + +pkg_file=$dest_dir/${pkg}_${version}_${arch}.ipk +rm -f $pkg_file +( cd $tmp_dir && $TAR --format=gnu --sort=name -cf - --mtime="$TIMESTAMP" ./debian-binary ./data.tar.gz ./control.tar.gz | $GZIP -n - > $pkg_file ) + +rm $tmp_dir/debian-binary $tmp_dir/data.tar.gz $tmp_dir/control.tar.gz +rmdir $tmp_dir + +echo "Packaged contents of $pkg_dir into $pkg_file" diff --git a/applications/luci-app-store/root/bin/is-opkg b/applications/luci-app-store/root/bin/is-opkg index 9af2d18..d24dbe4 100755 --- a/applications/luci-app-store/root/bin/is-opkg +++ b/applications/luci-app-store/root/bin/is-opkg @@ -1,10 +1,14 @@ #!/bin/sh +#set -x +#IS_DEBUG=1 IS_ROOT=/tmp/is-root DL_DIR=${IS_ROOT}/tmp/dl LISTS_DIR_O=/tmp/opkg-lists LISTS_DIR=${IS_ROOT}${LISTS_DIR_O} OPKG_CONF_DIR=${IS_ROOT}/etc/opkg +APP_LIST_FILE=/etc/istore/app.list +BACKUP_CONFIG_FILE=/etc/config/istore FEEDS_SERVER=https://istore.linkease.com/repo ARCH=`jsonfilter -i /etc/.app_store.id -e '$.arch'` @@ -59,7 +63,7 @@ update() { update_if_outdate() { local idle_t=$((`date '+%s'` - `date -r ${IS_ROOT}/.last_force_ts '+%s' 2>/dev/null || echo '0'`)) - [ $idle_t -gt ${1:-120} ] || return 2 + [ $idle_t -gt ${1:-120} ] || return 1 update || return 1 touch ${IS_ROOT}/.last_force_ts return 0 @@ -83,13 +87,7 @@ do_self_upgrade() { if opkg_wrap info ${ISTORE_PKG} | grep -qF not-installed ; then true else - update_if_outdate - local code=$? - [ "$code" = 1 ] && return 1 - if [ "$code" = 2 ] || ! opkg_wrap info ${ISTORE_PKG} | grep -qF not-installed; then - echo "already the latest version!" >&2 - return 1 - fi + update_if_outdate || return 1 fi opkg_wrap upgrade ${ISTORE_PKG} } @@ -116,17 +114,306 @@ new_upgrade() { wrapped_in_update upgrade "$@" } +opkg_list_installed_packages() { + target=$1 + case $target in + "preinstalled") + OPKG_INFO_DIR="/rom/usr/lib/opkg/info" + ;; + "userinstalled") + OPKG_INFO_DIR="/overlay/upper/usr/lib/opkg/info" + ;; + "allinstalled") + OPKG_INFO_DIR="/usr/lib/opkg/info" + ;; + *) + echo "invalid target" + exit + ;; + esac + + awk -v D="cd $OPKG_INFO_DIR &&" 'BEGIN { + C=D"ls *.list" + S="sort -n" + while(C|getline>0) { + P=substr(F=$1,1,length($1)-5) + J=D"du -sk $(cat "F")" + s=0 + while(J|getline>0) s+=$1 + close(J) + t+=s + print s" "P|S + } + close(S) + }' +} + +ipk_build() { + PKG_NAME_TEMP=$1 + IPK_OUTPUT_DIR=$2 + + UCI_BAK_DIR="/etc/istore/uci-defaults_bak/" + UCI_DEF_DIR="etc/uci-defaults" + OPKG_INFO_DIR="/usr/lib/opkg/info/" + + [ -n "${PKG_NAME_TEMP}" ] || exit 1 + #get real pkg name in opkg + PKG_NAME_TEMP=`cat ${IS_ROOT}/all_installed_package.list | sort -u | grep "^${PKG_NAME_TEMP}" | head -n 1` + [ -n "${PKG_NAME_TEMP}" ] || exit 1 + + PKG_NAME=`cat ${OPKG_INFO_DIR}${PKG_NAME_TEMP}.control | grep "^Package: " | cut -d ' ' -f2` + PKG_VER=`cat ${OPKG_INFO_DIR}${PKG_NAME}.control | grep "^Version: " | cut -d ' ' -f2` + PKG_ARCH=`cat ${OPKG_INFO_DIR}${PKG_NAME}.control | grep "^Architecture: " | cut -d ' ' -f2` + IPK_FILE_NAME="${PKG_NAME}_${PKG_VER}_${PKG_ARCH}" + + rm -rf ${IS_ROOT}/${IPK_FILE_NAME} + mkdir -p ${IS_ROOT}/${IPK_FILE_NAME} + + #(1)make CONTROL dir; (2)copy control file to dir + cd ${IS_ROOT}/${IPK_FILE_NAME} + mkdir -p CONTROL + for control_file in `ls ${OPKG_INFO_DIR}${PKG_NAME}.* | grep -v ".list$"`; do + file=${control_file##*/} + suffix=${file##*.} + cp ${control_file} CONTROL/${suffix} + done + + #(1)make DATA depend dir; (2)copy uci-defaults_bak file to dir; (3)copy other file to dir + for pkgfile in `cat ${OPKG_INFO_DIR}${PKG_NAME}.list | cut -b 2-`; do + file=${pkgfile##*/} + path=${pkgfile%/*} + mkdir -p ${path} + if [ `echo "${path}" | grep "^${UCI_DEF_DIR}"` ]; then + cp "${UCI_BAK_DIR}${file}" "${pkgfile}" + else + cp "/${pkgfile}" "${pkgfile}" + fi + done + + #call ipkg-build script to build ipk + ipkg-build ${IS_ROOT}/${IPK_FILE_NAME} ${IPK_OUTPUT_DIR} + echo "${IPK_FILE_NAME}.ipk" >> ${IPK_OUTPUT_DIR}/appdepipk.list + + [ -n "${IS_DEBUG}" ] || rm -rf ${IS_ROOT}/${IPK_FILE_NAME} +} + +# if arg is NULL, use light backup, otherwise use local backup +backup() { + [ -n "$1" ] && BACKUP_PATH=$1 + + #1.add all istore self data to sysupgrade config file, + #sysupgrade will backup/restore it auto when flash new firmware + echo "/etc/.app_store.id" > /lib/upgrade/keep.d/luci-app-store + cat /usr/lib/opkg/info/luci-app-store.list >> /lib/upgrade/keep.d/luci-app-store + echo "/etc/rc.d/S45istore" >> /lib/upgrade/keep.d/luci-app-store + echo "/etc/istore/uci-defaults_bak" >> /lib/upgrade/keep.d/luci-app-store + echo "${APP_LIST_FILE}" >> /lib/upgrade/keep.d/luci-app-store + echo "${BACKUP_CONFIG_FILE}" >> /lib/upgrade/keep.d/luci-app-store + + #2.backup all installed package lists to config file + update #if want not depend this, need record package list by istore to file when is-opkg update + + #get feed list + opkg_conf_list="meta all arch" + feed_name_list="" + for conf in ${opkg_conf_list}; do + feed_name=`cat ${OPKG_CONF_DIR}/${conf}.conf | cut -d ' ' -f2` + feed_name_list="${feed_name} ${feed_name_list}" + done + [ -n "${IS_DEBUG}" ] && echo ${feed_name_list} + + istore_package_list="" + #get istore package list + for feed_name in ${feed_name_list}; do + package_list=`cat ${LISTS_DIR}/${feed_name} | gunzip | grep "^Package: " | cut -d ' ' -f2` + istore_package_list="${package_list} ${istore_package_list}" + done + [ -n "${IS_DEBUG}" ] && echo ${istore_package_list} + + #write istore package list to file + echo ${istore_package_list} | tr " " "\n" | sort -n | uniq > ${IS_ROOT}/istore_support_package.list + + #write all installed package list to file + opkg_list_installed_packages "allinstalled" 2>/dev/null | cut -d ' ' -f2 | sort -u > ${IS_ROOT}/all_installed_package.list + + #write user installed package list to file + opkg_list_installed_packages "userinstalled" 2>/dev/null | cut -d ' ' -f2 | sort -u > ${IS_ROOT}/user_installed_package.list + + #write system pre installed package list to file + opkg_list_installed_packages "preinstalled" 2>/dev/null | cut -d ' ' -f2 | sort -u > ${IS_ROOT}/pre_installed_package.list + + #write installed package list by istore feed to file + cat ${IS_ROOT}/istore_support_package.list ${IS_ROOT}/user_installed_package.list | \ + sort -n | uniq -d > ${IS_ROOT}/istore_installed_package.list + + #if no input backup path, only back app.list + mkdir -p /etc/istore + cp ${IS_ROOT}/istore_installed_package.list ${APP_LIST_FILE} + echo "backup installed package list to ${APP_LIST_FILE}" + + if [ ! -n "${BACKUP_PATH}" ]; then + echo "backup success" + exit 0 + fi + + #write installed packages and depends list by istore feed to file by depend sequence + appdep_list="" + temp_list=`cat ${IS_ROOT}/istore_installed_package.list | sed 's/^/\t/'` + while [ -n "${temp_list}" ] + do + #get real pkg name + for PKG_NAME_TEMP in ${temp_list}; do + REAL_PKG_NAME=`cat ${IS_ROOT}/all_installed_package.list | sort -u | grep "^${PKG_NAME_TEMP}" | head -n 1` + if [ "${REAL_PKG_NAME}" != "${PKG_NAME_TEMP}" ]; then + temp_list=`echo "${temp_list}" | sed 's/^\t'"${PKG_NAME_TEMP}"'$/\t'"${REAL_PKG_NAME}"'/'` + fi + done + + appdep_list=`echo -e "${temp_list}\n${appdep_list}"` + [ -n "${IS_DEBUG}" ] && echo -e "temp_list:\n""${temp_list}" + [ -n "${IS_DEBUG}" ] && echo -e "appdep_list:\n""${appdep_list}" + + temp_list=`echo "${temp_list}" | xargs opkg depends | grep -v "depends on:" | grep -v " (>= " | grep -v " (= " | sort -u` + done + + appdep_list_all=`echo "${appdep_list}" | cut -f2 | grep -v "^$" | awk '!seen[$0]++'` + [ -n "${IS_DEBUG}" ] && echo -e "appdep_list_all:\n""${appdep_list_all}" + echo "${appdep_list_all}" > ${IS_ROOT}/appdep.list + + + #3.rebuild all istore installed package to ipk and backup to userdata partation + if [ ! -d "${BACKUP_PATH}" ];then + echo "invalid backup path, can not backup ipk" + exit 1 + fi + + # 4. create dir + date=$(date +%Y-%m%d-%H%M) + if [ ! -d "$BACKUP_PATH/backup_istore_$date" ];then + mkdir $BACKUP_PATH/backup_istore_$date + fi + cp ${IS_ROOT}/istore_installed_package.list $BACKUP_PATH/backup_istore_$date/app.list + cp ${IS_ROOT}/appdep.list $BACKUP_PATH/backup_istore_$date/appdep.list + + #only backup non pre installed ipk + cp ${IS_ROOT}/appdep.list ${IS_ROOT}/appdep_strip.list + for pre_installed_pkg in `cat ${IS_ROOT}/appdep.list ${IS_ROOT}/pre_installed_package.list | sort -n | uniq -d`; do + sed -i '/^'"$pre_installed_pkg"'$/d' ${IS_ROOT}/appdep_strip.list + done + + rm -f $BACKUP_PATH/backup_istore_$date/appdepipk.list + echo "build ipk" + for pkg_name in `cat ${IS_ROOT}/appdep_strip.list`; do + ipk_build ${pkg_name} $BACKUP_PATH/backup_istore_$date + done + + # 5. create tar.gz file,and remove fir + 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 + rm -rf $BACKUP_PATH/backup_istore_$date + echo "backup success" +} + +# if arg is NULL, use light backup, otherwise use local backup +restore() { + if [ -n "$1" ]; then + BACKUP_PATH_FILE=$1 + else + echo "install package by ${APP_LIST_FILE}" + update + for app in `cat ${APP_LIST_FILE}`; do + #skip resotre istore self + [ "A${app}" == "A""luci-app-store" ] && continue + opkg_wrap install ${app} + done + exit 0 + fi + + if [ ! -f "${BACKUP_PATH_FILE}" ];then + echo "invalid backup file, can not restore ipk" + exit 1 + fi + + #1. Unzip file to dir + BACKUP_PATH_FILE_NAME=${BACKUP_PATH_FILE##*/} + BACKUP_PATH=/tmp/${BACKUP_PATH_FILE_NAME%.backup.tar.gz*} + if [ -d "$BACKUP_PATH" ];then + rm -rf $BACKUP_PATH + fi + mkdir -p $BACKUP_PATH + echo "unpack input file..." + # fix tar path error + tar -zxf ${BACKUP_PATH_FILE} -C /tmp/ + + echo "check file" + if [ ! -f "${BACKUP_PATH}/appdep.list" ];then + echo "no available appdep.list, can not restore ipk" + exit 1 + fi + echo "check success" + + #2. install ipk by backup path + echo "restore begin" + for app in `cat ${BACKUP_PATH}/appdepipk.list`; do + opkg_wrap install ${BACKUP_PATH}/${app} + done + + #3. rm dir + rm -rf ${BACKUP_PATH} + echo "restore success" +} + +get_support_backup_features() { + echo "light_backup" + #istore custom img mean support local_backup + if [ -f /etc/istore_img_flag ];then + echo "local_backup" + fi +} + +get_backup_app_list_file_path() { + echo "${APP_LIST_FILE}" +} + +get_backup_app_list() { + if [ ! -f "${APP_LIST_FILE}" ];then + echo "no app.list, can not get backup app list" + exit 1 + fi + cat ${APP_LIST_FILE} +} + +get_available_backup_file_list() { + if [ -n "$1" ]; then + for backup_file in `ls $1/*.backup.tar.gz`; do + filename=${backup_file##*/} + echo "${filename}" + done + else + echo "input backup path is null" + exit 1 + fi +} + usage() { echo "usage: is-opkg sub-command [arguments...]" echo "where sub-command is one of:" - echo " update Update list of available packages" - echo " upgrade Upgrade package(s)" - echo " install Install package(s)" - echo " remove Remove package(s)" - echo " info [pkg|regexp] Display all info for " - echo " list-upgradable List installed and upgradable packages" - echo " check_self_upgrade Check iStore upgrade" - echo " do_self_upgrade Upgrade iStore" + echo " update Update list of available packages" + echo " upgrade Upgrade package(s)" + echo " install Install package(s)" + echo " remove Remove package(s)" + echo " info [pkg|regexp] Display all info for " + echo " list-upgradable List installed and upgradable packages" + echo " check_self_upgrade Check iStore upgrade" + echo " do_self_upgrade Upgrade iStore" + echo " backup [dir] Backup all installed package(s) to [directory]" + echo " restore [dir] Restore package(s) by [directory]" + echo " get_support_backup_features get device support backup features" + echo " get_backup_app_list_file_path get light backup app list file path" + echo " get_backup_app_list get light backup app list" + echo " get_available_backup_file_list get local available backup file list" + echo " opkg sys opkg wrap" } is_init >/dev/null 2>&1 @@ -156,6 +443,28 @@ case $action in "do_self_upgrade") do_self_upgrade ;; + "get_support_backup_features") + get_support_backup_features + ;; + "backup") + backup "$@" + ;; + "restore") + restore "$@" + ;; + "get_backup_app_list_file_path") + get_backup_app_list_file_path + ;; + "get_backup_app_list") + get_backup_app_list + ;; + "get_available_backup_file_list") + get_available_backup_file_list "$@" + ;; + "opkg") + opkg_wrap "$@" + ;; + *) usage ;; diff --git a/applications/luci-app-store/root/usr/share/opkg/intercept/rm b/applications/luci-app-store/root/usr/share/opkg/intercept/rm new file mode 100755 index 0000000..9e50a80 --- /dev/null +++ b/applications/luci-app-store/root/usr/share/opkg/intercept/rm @@ -0,0 +1,7 @@ +#!/bin/sh +for i in "$@"; do + echo "$i" | grep -s -q "/etc/uci-defaults/" \ + && mkdir -p /etc/istore/uci-defaults_bak \ + && cp -f "$i" /etc/istore/uci-defaults_bak/ +done +/bin/rm "$@"