mirror of
https://github.com/EliasKotlyar/Xiaomi-Dafang-Hacks.git
synced 2025-09-02 12:43:02 +02:00
* Add repo option to autoupdate.sh * Fix repo option in autoupdate.sh * Use local repo when checking for updates * Use default repo if non given in VERSION file in autoupdates.sh * Pass custom repo to web ui and update cgi * Add custom firmware update to web ui * Fix update messages * Fix update start arguments * Fix update input labels * Add custom upgrade button when on custom firmware
421 lines
13 KiB
Bash
Executable File
421 lines
13 KiB
Bash
Executable File
#!/bin/sh
|
|
##########################################################################
|
|
# Github autodownload script
|
|
# See usage for help
|
|
# Edit the global variables to change the repo and initial folder
|
|
# Depends on curl, jq (json parser), openssl (SHA calculation)
|
|
|
|
# owner name and repo name
|
|
REPO="EliasKotlyar/Xiaomi-Dafang-Hacks"
|
|
# Branch to use
|
|
BRANCH="master"
|
|
# Initial remote folder
|
|
REMOTEFOLDER="firmware_mod"
|
|
# Default destination foler
|
|
DESTFOLDER="/system/sdcard/"
|
|
DESTOVERRIDE="/tmp/Update"
|
|
# The list of exclude, can have multple filter with "*.conf|*.sh"
|
|
EXCLUDEFILTER="*.conf|*.user|passwd|shadow"
|
|
GITHUBURL="https://api.github.com/repos"
|
|
GITHUBURLRAW="https://raw.githubusercontent.com"
|
|
CURL="/system/sdcard/bin/curl -k -L"
|
|
JQ="/system/sdcard/bin/jq"
|
|
SHA="/system/sdcard/bin/openssl dgst -sha256"
|
|
BASENAME="/system/sdcard/bin/busybox basename"
|
|
FIND="/system/sdcard/bin/busybox find"
|
|
VERSION_FILE='/system/sdcard/VERSION'
|
|
COMMITS_FILE='/tmp/.lastcommit'
|
|
|
|
|
|
|
|
TMPFILE=/tmp/update.tmp
|
|
BACKUPEXT=.backup
|
|
_PRINTONLY=0
|
|
_V=0
|
|
_FORCE=0
|
|
_FORCEREBOOT=0
|
|
_BACKUP=0
|
|
|
|
_PROGRESS=0
|
|
_NBFILES=0
|
|
_NBTOTALFILES=0
|
|
##########################################################################
|
|
|
|
usage()
|
|
{
|
|
echo "Usage: $1 [OPTIONS]"
|
|
echo "$1 will update a local folder with the ${REPO} github repo (first copy all the files in ${DESTOVERRIDE}, stop services and reboot"
|
|
echo "Usage this script to update the ${REPO} github repo from ${BRANCH} (default) branch"
|
|
echo "Options:"
|
|
echo "-b (--backup) backup erased file (add extension ${BACKUPEXT} to the local file before ovewrite it) "
|
|
echo "-x (--repo) to set the repo"
|
|
echo "-r (--branch) to set the branch"
|
|
echo "-f (--force) force update"
|
|
echo "-d (--dest) set the destination folder (default is ${DESTFOLDER})"
|
|
echo "-p (--print) print action only, do nothing"
|
|
echo "-s (--steps) add progress in file /tmp/progress"
|
|
|
|
echo "-v (--verbose) for verbose"
|
|
echo "-u (--user) githup login/password (not mandatory, but sometime anonymous account get banned)"
|
|
echo "-t (--token) github API token"
|
|
echo "-h (--help) for this help"
|
|
echo
|
|
echo "Note that ${EXCLUDEFILTER} will be excluded"
|
|
echo "Examples:"
|
|
echo "Update all files if needed >$1 -d /system/sdcard (-f to force update)"
|
|
}
|
|
|
|
##########################################################################
|
|
# Function to get user input for yes/no/all
|
|
# print the result (yes,no,all)
|
|
ask_yes_or_no() {
|
|
read R
|
|
case $(echo ${R} | tr '[A-Z]' '[a-z]') in
|
|
y|yes) echo "yes" ;;
|
|
a|all) echo "all" ;;
|
|
*) echo "no" ;;
|
|
esac
|
|
}
|
|
|
|
##########################################################################
|
|
# Log string if verbose is set
|
|
log ()
|
|
{
|
|
if [ ${_V} -eq 1 ]; then
|
|
echo "$@"
|
|
fi
|
|
}
|
|
|
|
##########################################################################
|
|
# Log string on std error
|
|
logerror ()
|
|
{
|
|
echo "$@" 1>&2
|
|
}
|
|
|
|
##########################################################################
|
|
# Log string on std error
|
|
progress()
|
|
{
|
|
if [ ${_PROGRESS} -eq 1 ]; then
|
|
_NBFILES=$((${_NBFILES} + 1))
|
|
echo -n $((${_NBFILES} *100 / ${_NBTOTALFILES} )) > /tmp/progress
|
|
# echo "file = ${_NBFILES}, total=${_NBTOTALFILES} = $((${_NBFILES} *100 / ${_NBTOTALFILES} ))"
|
|
fi
|
|
}
|
|
|
|
##########################################################################
|
|
# If "printonly" action is selected print the action to do (but don't do it
|
|
# If not execute it
|
|
action()
|
|
{
|
|
if [ ${_PRINTONLY} -eq 1 ]; then
|
|
echo "Action: $@"
|
|
else
|
|
eval "$@"
|
|
fi
|
|
return $?
|
|
}
|
|
##########################################################################
|
|
# Check if $1 macth with the excluded filter
|
|
ismatch()
|
|
{
|
|
in=$(${BASENAME} ${1})
|
|
for filter in $(echo ${EXCLUDEFILTER} | sed "s/|/ /g")
|
|
do
|
|
if [ "${in#$filter}" == "" ]; then
|
|
echo match
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
echo notmatch
|
|
}
|
|
|
|
##########################################################################
|
|
# Print the files from repo of the folder $1
|
|
# Recursive call (for folder)
|
|
getfiles()
|
|
{
|
|
if echo "${1}" | grep -q "API rate limit exceeded"; then
|
|
logerror "Github limit exceeded, try with an account (-u option)"
|
|
exit 1
|
|
else
|
|
for row in $(echo "${1}" | ${JQ} '.[]| select(.type=="file") | .download_url' ); do
|
|
filetoget=$(echo "${row}" | tr -d '"')
|
|
echo ${filetoget}
|
|
done
|
|
|
|
for row in $(echo "${1}" | ${JQ} '.[]| select(.type == "dir") | .path' ); do
|
|
flder=$(echo "${row}" | tr -d '"')
|
|
next=$(curl -s https://api.github.com/repos/${REPO}/contents/${flder}?ref=${BRANCH})
|
|
getfiles "${next}"
|
|
done
|
|
fi
|
|
}
|
|
##########################################################################
|
|
# Let some time before rebooting
|
|
countdownreboot()
|
|
{
|
|
i=10
|
|
while [ ${i} -gt 0 ];
|
|
do
|
|
echo "$i seconds remaining before reboot (Press control-c to abort)";
|
|
i=$((${i} - 1))
|
|
sleep 1;
|
|
done
|
|
action reboot
|
|
}
|
|
##########################################################################
|
|
# Generate VERSION file
|
|
generateVersionFile ()
|
|
{
|
|
echo "{\"date\":\"${REMOTECOMMITDATE}\",\"repo\":\"${REPO}\",\"branch\":\"${BRANCH}\",\"commit\":\"${REMOTECOMMITID}\"}" > $VERSION_FILE
|
|
}
|
|
##########################################################################
|
|
# Curl with optional authentication
|
|
curl ()
|
|
{
|
|
if [ -n "$_TOKEN" ]; then
|
|
$CURL -H "Authorization: token $_TOKEN" "$@"
|
|
elif [ -n "$_USER" ]; then
|
|
$CURL -u "$_USER" "$@"
|
|
else
|
|
$CURL "$@"
|
|
fi
|
|
}
|
|
##########################################################################
|
|
# Script real start
|
|
|
|
while [ $# -gt 0 ]
|
|
do
|
|
arg="$1"
|
|
case ${arg} in
|
|
"")
|
|
;;
|
|
-v | --verbose)
|
|
_V=1
|
|
shift
|
|
;;
|
|
-f | --force)
|
|
_FORCE=1
|
|
_FORCEREBOOT=1
|
|
shift
|
|
;;
|
|
-d | --dest)
|
|
DESTFOLDER="$2/"
|
|
shift
|
|
shift
|
|
;;
|
|
-b | --backup)
|
|
_BACKUP=1;
|
|
shift
|
|
;;
|
|
-p | --print)
|
|
_PRINTONLY=1
|
|
shift
|
|
;;
|
|
-u | --user)
|
|
_USER="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
-t | --token)
|
|
_TOKEN="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
-s | --steps)
|
|
_PROGRESS=1;
|
|
shift
|
|
;;
|
|
-x | --repo)
|
|
REPO=$2;
|
|
shift
|
|
shift
|
|
;;
|
|
-r | --branch)
|
|
BRANCH=$2
|
|
shift
|
|
shift
|
|
;;
|
|
*|-h |\? | --help)
|
|
usage $0
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
log "Starting AutoUpdate on branch ${BRANCH}"
|
|
|
|
######################################################""
|
|
# Get date and last commit ID from Github
|
|
curl -s ${GITHUBURL}/${REPO}/commits/${BRANCH} --output $COMMITS_FILE
|
|
REMOTECOMMITDATE=$(${JQ} -r '.commit .author .date' ${COMMITS_FILE})
|
|
REMOTECOMMITID=$(${JQ} -r '.sha[0:7]' ${COMMITS_FILE} )
|
|
|
|
if [ ${_FORCE} = 1 ]; then
|
|
log "Forcing update."
|
|
fi
|
|
|
|
if [ ${_PRINTONLY} = 1 ]; then
|
|
log "Print actions only, do nothing."
|
|
fi
|
|
|
|
if [ ${_BACKUP} = 1 ]; then
|
|
log "Backing up files."
|
|
fi
|
|
|
|
action "rm -rf ${DESTOVERRIDE} 2>/dev/null"
|
|
|
|
if [ -f "$VERSION_FILE" ]; then
|
|
LOCALCOMMITID=$(${JQ} -r .commit ${VERSION_FILE})
|
|
LOCALREPO=$(${JQ} -r .repo ${VERSION_FILE})
|
|
if [ -z "$LOCALREPO" ]; then LOCALREPO="$REPO"; fi
|
|
if [ ${LOCALREPO} = ${REPO} ] && [ ${LOCALCOMMITID} = ${REMOTECOMMITID} ]; then
|
|
logerror "You are currently on the latest version"
|
|
echo "You are currently on the latest version"
|
|
exit 1
|
|
elif [ ${LOCALREPO} = ${REPO} ]; then
|
|
echo "Need to upgrade from ${LOCALCOMMITID} to ${REMOTECOMMITID}"
|
|
log "Getting list of remote files."
|
|
FILES=$(curl -s ${GITHUBURL}/${REPO}/compare/${LOCALCOMMITID}...${REMOTECOMMITID} | ${JQ} -r '.files[].raw_url' | grep ${REMOTEFOLDER})
|
|
else
|
|
echo "Repo has changed. Upgrade to last commit ${REMOTECOMMITID}"
|
|
log "Getting list of remote files."
|
|
FIRST=$(curl -s ${GITHUBURL}/${REPO}/contents/${REMOTEFOLDER}?ref=${BRANCH})
|
|
FILES=$(getfiles "${FIRST}")
|
|
fi
|
|
else
|
|
echo "Version file missing. Upgrade to last commit ${REMOTECOMMITID}"
|
|
log "Getting list of remote files."
|
|
FIRST=$(curl -s ${GITHUBURL}/${REPO}/contents/${REMOTEFOLDER}?ref=${BRANCH})
|
|
FILES=$(getfiles "${FIRST}")
|
|
fi
|
|
|
|
if [ $_PROGRESS = 1 ]; then
|
|
_NBTOTALFILES=$(echo $FILES | wc -w)
|
|
log Number of file to update $_NBTOTALFILES
|
|
echo -n 0 > /tmp/progress
|
|
fi
|
|
|
|
# For all the repository files
|
|
for i in ${FILES}
|
|
do
|
|
progress
|
|
# String to remove to get the local path
|
|
LOCALFILE=$(echo ${i} | awk -F ${REMOTEFOLDER}/ '{print $2}')
|
|
# Remove files that match the filter
|
|
res=$(ismatch ${LOCALFILE})
|
|
if [ "$res" == "match" ]; then
|
|
echo "${LOCALFILE} is excluded due to filter."
|
|
continue
|
|
fi
|
|
# Get the file temporally to calculate SHA
|
|
curl -s ${i} -o ${TMPFILE} 2>/dev/null
|
|
if [ ! -f ${TMPFILE} ]; then
|
|
echo "Can not get remote file $i, exiting."
|
|
exit 1
|
|
fi
|
|
# sometimes zero byte files are received, which overwrite the local files, we ignore those files
|
|
# exception: files that are hidden i.e. start with dot. Ex: files like ".gitkeep"
|
|
if [[ ! -s ${TMPFILE} ]] && [[ $(basename ${LOCALFILE} | cut -c1-1) != "." ]]; then
|
|
echo "Received zero byte file $i, exiting."
|
|
exit 1
|
|
fi
|
|
# Check the file exists in local
|
|
if [ -f "${DESTFOLDER}/${LOCALFILE}" ]; then
|
|
REMOTESHA=$(${SHA} ${TMPFILE} 2>/dev/null | cut -d "=" -f 2)
|
|
# Calculate the remote and local SHA
|
|
LOCALSHA=$(${SHA} ${DESTFOLDER}${LOCALFILE} 2>/dev/null | cut -d "=" -f 2)
|
|
|
|
# log "SHA of $LOCALFILE is ${LOCALSHA} ** remote is ${REMOTESHA}"
|
|
if [ "${REMOTESHA}" = "${LOCALSHA}" ] ; then
|
|
echo "${LOCALFILE} is up to date."
|
|
else
|
|
if [ ${_FORCE} = 1 ]; then
|
|
echo "${LOCALFILE} updated."
|
|
action "mkdir -p $(dirname ${DESTOVERRIDE}/${LOCALFILE}) 2>/dev/null"
|
|
if [ ${_BACKUP} = 1 ]; then
|
|
action cp ${DESTFOLDER}${LOCALFILE} ${DESTOVERRIDE}/${LOCALFILE}${BACKUPEXT}
|
|
fi
|
|
action mv ${TMPFILE} ${DESTOVERRIDE}/${LOCALFILE}
|
|
else
|
|
echo "${LOCALFILE} needs to be updated. Overwrite?"
|
|
echo "[Y]es or [N]o or [A]ll?"
|
|
rep=$(ask_yes_or_no )
|
|
if [ "${rep}" = "no" ]; then
|
|
echo "${LOCALFILE} not updated"
|
|
rm -f ${TMPFILE} 2>/dev/null
|
|
else
|
|
action "mkdir -p $(dirname ${DESTOVERRIDE}/${LOCALFILE}) 2>/dev/null"
|
|
if [ ${_BACKUP} = 1 ]; then
|
|
action cp ${DESTFOLDER}${LOCALFILE} ${DESTOVERRIDE}/${LOCALFILE}${BACKUPEXT}
|
|
fi
|
|
action mv ${TMPFILE} ${DESTOVERRIDE}/${LOCALFILE}
|
|
|
|
fi
|
|
if [ "${rep}" = "all" ]; then
|
|
_FORCE=1
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
if [ ${_FORCE} = 1 ]; then
|
|
echo "${LOCALFILE} created."
|
|
action "mkdir -p $(dirname ${DESTOVERRIDE}/${LOCALFILE}) 2>/dev/null"
|
|
action mv ${TMPFILE} ${DESTOVERRIDE}/${LOCALFILE}
|
|
else
|
|
echo "${LOCALFILE} doesn't exist, create it?"
|
|
echo "[Y]es or [N]o or [A]ll ?"
|
|
rep=$(ask_yes_or_no )
|
|
if [ "${rep}" = "no" ]; then
|
|
echo "${LOCALFILE} not created."
|
|
rm -f ${TMPFILE} 2>/dev/null
|
|
else
|
|
action "mkdir -p $(dirname ${DESTOVERRIDE}/${LOCALFILE}) 2>/dev/null"
|
|
action mv ${TMPFILE} ${DESTOVERRIDE}/${LOCALFILE}
|
|
fi
|
|
if [ "${rep}" = "all" ]; then
|
|
_FORCE=1
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ $_PROGRESS = 1 ]; then
|
|
echo -n 100 > /tmp/progress
|
|
fi
|
|
|
|
|
|
if [ -d ${DESTOVERRIDE} ] && [ $(ls -l ${DESTOVERRIDE}/* | wc -l 2>/dev/null) > 1 ]; then
|
|
echo "--------------- Stopping services ---------"
|
|
for i in /system/sdcard/controlscripts/*; do
|
|
echo stopping $i
|
|
$i stop &> /dev/null
|
|
done
|
|
pkill lighttpd.bin 2> /dev/null
|
|
pkill bftpd 2> /dev/null
|
|
|
|
echo "--------------- Updating files ----------"
|
|
action "cp -Rf ${DESTOVERRIDE}/* ${DESTFOLDER} 2>/dev/null"
|
|
action "rm -Rf ${DESTOVERRIDE}/* 2>/dev/null"
|
|
|
|
# Everythings was OK, save the date
|
|
generateVersionFile
|
|
echo "--------------- Reboot ------------"
|
|
if [ ${_FORCEREBOOT} = 1 ]; then
|
|
countdownreboot
|
|
else
|
|
echo "A reboot is needed, do you want to reboot now?"
|
|
echo "[Y]es or [N]o"
|
|
rep=$(ask_yes_or_no )
|
|
if [ "${rep}" = "yes" ]; then
|
|
countdownreboot
|
|
fi
|
|
fi
|
|
else
|
|
generateVersionFile
|
|
echo "No files to update."
|
|
fi
|