478 lines
15 KiB
Bash
Executable File
478 lines
15 KiB
Bash
Executable File
#!/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'`
|
|
|
|
# for istore self upgrade
|
|
ISTORE_PKG=luci-app-store
|
|
ISTORE_INDEX=https://istore.linkease.com/repo/all/store/Packages.gz
|
|
|
|
action=${1}
|
|
shift
|
|
|
|
is_init() {
|
|
mkdir -p ${DL_DIR} ${LISTS_DIR} ${IS_ROOT}/etc ${IS_ROOT}/var
|
|
|
|
cat /etc/opkg.conf | grep -v lists_dir | grep -v check_signature > ${IS_ROOT}/etc/opkg.conf
|
|
|
|
cp ${IS_ROOT}/etc/opkg.conf ${IS_ROOT}/etc/opkg_o.conf
|
|
|
|
echo >> ${IS_ROOT}/etc/opkg.conf
|
|
echo "lists_dir ext ${LISTS_DIR}" >> ${IS_ROOT}/etc/opkg.conf
|
|
echo >> ${IS_ROOT}/etc/opkg_o.conf
|
|
echo "lists_dir ext ${LISTS_DIR_O}" >> ${IS_ROOT}/etc/opkg_o.conf
|
|
|
|
cp -au /etc/opkg ${IS_ROOT}/etc/
|
|
[ -e ${IS_ROOT}/var/lock ] || ln -s /var/lock ${IS_ROOT}/var/lock
|
|
}
|
|
|
|
opkg_wrap() {
|
|
OPKG_CONF_DIR=${OPKG_CONF_DIR} opkg -f ${IS_ROOT}/etc/opkg.conf "$@"
|
|
}
|
|
|
|
fcurl() {
|
|
curl --fail --show-error "$@"
|
|
}
|
|
|
|
update() {
|
|
if [ -z "${ARCH}" ]; then
|
|
echo "Get architecture failed" >&2
|
|
echo "/etc/.app_store.id:" >&2
|
|
cat /etc/.app_store.id >&2
|
|
return 1
|
|
fi
|
|
|
|
fcurl -o ${OPKG_CONF_DIR}/meta.conf "${FEEDS_SERVER}/all/meta.conf" && \
|
|
fcurl -o ${OPKG_CONF_DIR}/all.conf "${FEEDS_SERVER}/all/isfeeds.conf" && \
|
|
fcurl -o ${OPKG_CONF_DIR}/arch.conf "${FEEDS_SERVER}/${ARCH}/isfeeds.conf" || \
|
|
return 1
|
|
|
|
opkg -f ${IS_ROOT}/etc/opkg_o.conf --offline-root ${IS_ROOT} update
|
|
|
|
return 0
|
|
}
|
|
|
|
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
|
|
update || return 1
|
|
touch ${IS_ROOT}/.last_force_ts
|
|
return 0
|
|
}
|
|
|
|
check_self_upgrade() {
|
|
local newest=`curl --connect-timeout 2 --max-time 5 -s ${ISTORE_INDEX} | gunzip | grep -FA10 "Package: ${ISTORE_PKG}" | grep -Fm1 'Version: ' | sed 's/^Version: //'`
|
|
local current=`grep -Fm1 'Version: ' /usr/lib/opkg/info/${ISTORE_PKG}.control | sed 's/^Version: //'`
|
|
if [ "v$newest" = "v" -o "v$current" = "v" ]; then
|
|
echo "Check version failed!" >&2
|
|
exit 255
|
|
fi
|
|
if [ "$newest" != "$current" ]; then
|
|
echo "$newest"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
do_self_upgrade() {
|
|
check_mtime || return 1
|
|
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
|
|
fi
|
|
opkg_wrap upgrade ${ISTORE_PKG}
|
|
}
|
|
|
|
check_mtime() {
|
|
find ${OPKG_CONF_DIR}/arch.conf -mtime -1 2>/dev/null | grep -q . || update
|
|
}
|
|
|
|
wrapped_in_update() {
|
|
check_mtime || return 1
|
|
opkg_wrap "$@" && return 0
|
|
update_if_outdate || return 1
|
|
opkg_wrap "$@"
|
|
}
|
|
|
|
new_upgrade() {
|
|
check_mtime || return 1
|
|
local metapkg=`echo "$@" | sed 's/ /\n/g' | grep -F app-meta-`
|
|
if [ -z "$metapkg" ] || opkg_wrap info $metapkg | grep -qF not-installed ; then
|
|
true
|
|
else
|
|
update_if_outdate
|
|
fi
|
|
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 <pkgs> Upgrade package(s)"
|
|
echo " install <pkgs> Install package(s)"
|
|
echo " remove <pkgs|regexp> Remove package(s)"
|
|
echo " info [pkg|regexp] Display all info for <pkg>"
|
|
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
|
|
|
|
case $action in
|
|
"update")
|
|
update
|
|
;;
|
|
"install")
|
|
wrapped_in_update install "$@"
|
|
;;
|
|
"upgrade")
|
|
new_upgrade "$@"
|
|
;;
|
|
"remove")
|
|
opkg_wrap --autoremove --force-removal-of-dependent-packages remove "$@"
|
|
;;
|
|
"info")
|
|
opkg_wrap info "$@"
|
|
;;
|
|
"list-upgradable")
|
|
opkg_wrap list-upgradable
|
|
;;
|
|
"check_self_upgrade")
|
|
check_self_upgrade
|
|
;;
|
|
"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
|
|
;;
|
|
esac
|