#!/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 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 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