Last active
April 3, 2017 21:07
-
-
Save ggiamarchi/830aa6495dfaff385a3ce5220a031712 to your computer and use it in GitHub Desktop.
rpi-update debug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -x | |
set -o nounset | |
set -o errexit | |
REPO_URI=${REPO_URI:-"https://github.com/Hexxeh/rpi-firmware"} | |
UPDATE_SELF=${UPDATE_SELF:-1} | |
UPDATE_URI="https://raw.githubusercontent.com/Hexxeh/rpi-update/master/rpi-update" | |
if [[ ${BOOT_PATH:-"unset"} == "unset" && ${ROOT_PATH:-"unset"} != "unset" ]] || | |
[[ ${BOOT_PATH:-"unset"} != "unset" && ${ROOT_PATH:-"unset"} == "unset" ]]; then | |
echo " *** You need to specify both ROOT_PATH and BOOT_PATH, or neither" | |
exit 1 | |
fi | |
if [[ ${BOOT_PATH:-"unset"} == "unset" ]]; then | |
NOOBS_CHECK=${NOOBS_CHECK:-1} | |
else | |
NOOBS_CHECK=${NOOBS_CHECK:-0} | |
fi | |
BRANCH=${BRANCH:-"master"} | |
ROOT_PATH=${ROOT_PATH:-"/"} | |
BOOT_PATH=${BOOT_PATH:-"/boot"} | |
WORK_PATH=${WORK_PATH:-"${ROOT_PATH}/root"} | |
SKIP_KERNEL=${SKIP_KERNEL:-0} | |
SKIP_SDK=${SKIP_SDK:-0} | |
SKIP_REPODELETE=${SKIP_REPODELETE:-0} | |
SKIP_BACKUP=${SKIP_BACKUP:-0} | |
SKIP_DOWNLOAD=${SKIP_DOWNLOAD:-0} | |
SKIP_WARNING=${SKIP_WARNING:-0} | |
WANT_SYMVERS=${WANT_SYMVERS:-0} | |
PRUNE_MODULES=${PRUNE_MODULES:-0} | |
RPI_UPDATE_UNSUPPORTED=${RPI_UPDATE_UNSUPPORTED:-0} | |
JUST_CHECK=${JUST_CHECK:-0} | |
GITHUB_API_TOKEN=${GITHUB_API_TOKEN:-""} | |
FW_REPO="${REPO_URI}.git" | |
FW_REPOLOCAL=${FW_REPOLOCAL:-"${WORK_PATH}/.rpi-firmware"} | |
FW_PATH="${BOOT_PATH}" | |
FW_MODPATH="${ROOT_PATH}/lib/modules" | |
FW_REV=${1:-""} | |
FW_REVFILE="${FW_PATH}/.firmware_revision" | |
[ "${RPI_UPDATE_UNSUPPORTED}" -ne 0 ] && echo -e "You appear to be trying to update firmware on an incompatible distribution. To force update, run the following:\nsudo -E RPI_UPDATE_UNSUPPORTED=0 rpi-update" && exit 1 | |
if command -v vcgencmd > /dev/null; then | |
vcgencmd get_config str | grep -qE "^kernel=" && echo -e "You appear to be using a custom kernel file.\nSkipping installation of new kernel, as bundled dtb files may be incompatible with your kernel." && SKIP_KERNEL=1 | |
fi | |
# Support for custom GitHub Auth Tokens | |
GITHUB_AUTH_PARAM="" | |
if [[ -n "${GITHUB_API_TOKEN}" ]]; then | |
echo " *** Using GitHub token for all requests." | |
GITHUB_AUTH_PARAM="--header \"Authorization: token ${GITHUB_API_TOKEN}\"" | |
fi | |
function update_self() { | |
echo " *** Performing self-update" | |
_tempFileName="$0.tmp" | |
if ! eval curl -Lfs ${GITHUB_AUTH_PARAM} --output "${_tempFileName}" "${UPDATE_URI}"; then | |
echo " !!! Failed to download update for rpi-update!" | |
echo " !!! Make sure you have ca-certificates installed and that the time is set correctly" | |
exit 1 | |
fi | |
OCTAL_MODE=$(stat -c '%a' "$0") | |
if ! chmod ${OCTAL_MODE} "${_tempFileName}" ; then | |
echo " !!! Failed: Error while trying to set mode on ${_tempFileName}" | |
exit 1 | |
fi | |
cat > "${WORK_PATH}/.updateScript.sh" << EOF | |
if mv "${_tempFileName}" "$0"; then | |
rm -- "\$0" | |
exec env UPDATE_SELF=0 /bin/bash "$0" "${FW_REV}" | |
else | |
echo " !!! Failed!" | |
fi | |
EOF | |
echo " *** Relaunching after update" | |
exec /bin/bash "${WORK_PATH}/.updateScript.sh" | |
} | |
function update_modules { | |
if [[ ${SKIP_KERNEL} -eq 0 ]]; then | |
echo " *** Updating kernel modules" | |
find "${FW_REPOLOCAL}/modules" -mindepth 1 -maxdepth 1 -type d | while read DIR; do | |
BASEDIR=$(basename "${DIR}") | |
rm -rf "${FW_MODPATH}/${BASEDIR}/kernel" | |
done | |
if [[ ${PRUNE_MODULES} -ne 0 ]]; then | |
find "${FW_MODPATH}" -mindepth 1 -maxdepth 1 -type d | while read DIR; do | |
COUNT=$(find ${DIR} -type f ! \( -name '*.ko' -o -name 'modules.*' \) | wc -l); | |
if [[ ${COUNT} -eq 0 ]]; then | |
echo "Pruning ${DIR}" | |
rm -rf ${DIR} | |
else | |
echo "Keeping ${DIR}" | |
fi | |
done | |
fi | |
cp -R "${FW_REPOLOCAL}/modules/"* "${FW_MODPATH}/" | |
find "${FW_REPOLOCAL}/modules" -mindepth 1 -maxdepth 1 -type d | while read DIR; do | |
BASEDIR=$(basename "${DIR}") | |
echo " *** depmod ${BASEDIR}" | |
depmod -b "${ROOT_PATH}" -a "${BASEDIR}" | |
done | |
else | |
echo " *** As requested, not updating kernel modules" | |
fi | |
} | |
function update_vc_libs { | |
echo " *** Updating VideoCore libraries" | |
if [[ -e ${ROOT_PATH}/bin/sh ]]; then | |
ELFOUTPUT=$(readelf -a "${ROOT_PATH}/bin/sh"; readelf -h "${ROOT_PATH}/bin/sh") | |
else | |
ELFOUTPUT="VFP_args" | |
fi | |
if [[ "${ELFOUTPUT}" != "${ELFOUTPUT/VFP_args/}" || \ | |
"${ELFOUTPUT}" != "${ELFOUTPUT/hard-float/}" ]]; then | |
echo " *** Using HardFP libraries" | |
cp -R "${FW_REPOLOCAL}/vc/hardfp/"* "${ROOT_PATH}/" | |
else | |
echo " *** Using SoftFP libraries" | |
cp -R "${FW_REPOLOCAL}/vc/softfp/"* "${ROOT_PATH}/" | |
fi | |
} | |
function update_sdk { | |
if [[ ${SKIP_SDK} -eq 0 ]]; then | |
echo " *** Updating SDK" | |
cp -R "${FW_REPOLOCAL}/vc/sdk/"* "${ROOT_PATH}/" | |
else | |
echo " *** As requested, not updating SDK" | |
fi | |
} | |
function show_notice { | |
local FULL_NOTICE=`eval curl -Lfs ${GITHUB_AUTH_PARAM} https://raw.githubusercontent.com/hexxeh/rpi-firmware/${FW_REV}/NOTICE.md` | |
local NOTICE=$(echo "$FULL_NOTICE" | tail -n+2) | |
if [ -z "$NOTICE" ]; then | |
return | |
fi | |
local NOTICE_HASH_HEAD=$(echo "$FULL_NOTICE" | head -1) | |
if [ $(echo "${NOTICE_HASH_HEAD}" | awk -F: '{print $1}') == "HASH" ]; then | |
local NOTICE_HASH_EXISTS=true | |
local NOTICE_HASH=$(echo "${NOTICE_HASH_HEAD}" | awk '{print $2}') | |
else | |
local NOTICE_HASH_EXISTS=false | |
fi | |
if [ -f "$FW_REVFILE" ]; then | |
local LOCAL_HASH=$(cat "$FW_REVFILE") | |
else | |
local LOCAL_HASH=0 | |
fi | |
if ${NOTICE_HASH_EXISTS}; then | |
local NEW_HASH=${FW_REV} | |
local LOCAL_lt_NOTICE=$(compare_hashes ${LOCAL_HASH} lt ${NOTICE_HASH}) | |
local NEW_ge_NOTICE=$(compare_hashes ${NEW_HASH} ge ${NOTICE_HASH}) | |
if ! ${LOCAL_lt_NOTICE} && ! ${NEW_ge_NOTICE}; then | |
return | |
fi | |
fi | |
echo "$NOTICE" | |
if ! echo "$NOTICE" | grep -q WARNING; then | |
return | |
fi | |
if [[ ${SKIP_WARNING} -ne 0 ]]; then | |
return | |
fi | |
read -p "Would you like to proceed? (y/N)" -n 1 -r -s | |
echo "" | |
if ! [[ $REPLY =~ ^[Yy]$ ]]; then | |
exit 1; | |
fi | |
} | |
function update_firmware { | |
echo " *** Updating firmware" | |
rm -rf "${FW_PATH}/"*.elf | |
rm -rf "${FW_PATH}/"bootcode.bin | |
cp "${FW_REPOLOCAL}/"*.elf "${FW_PATH}/" | |
cp "${FW_REPOLOCAL}/"*.bin "${FW_PATH}/" | |
cp "${FW_REPOLOCAL}/"*.dat "${FW_PATH}/" | |
if [[ ${SKIP_KERNEL} -eq 0 ]]; then | |
cp "${FW_REPOLOCAL}/"*.img "${FW_PATH}/" | |
if [[ -n $(shopt -s nullglob; echo "${FW_REPOLOCAL}/"*.dtb*) ]]; then | |
cp "${FW_REPOLOCAL}/"*.dtb* "${FW_PATH}/" | |
fi | |
if [[ -n $(shopt -s nullglob; echo "${FW_REPOLOCAL}/overlays/"*.dtb*) ]]; then | |
mkdir -p "${FW_PATH}/overlays" | |
cp "${FW_REPOLOCAL}/overlays/"*.dtb* "${FW_PATH}/overlays/" | |
if [[ -f "${FW_REPOLOCAL}/overlays/README" ]]; then | |
cp "${FW_REPOLOCAL}/overlays/README" "${FW_PATH}/overlays/" | |
fi | |
fi | |
else | |
echo " *** As requested, not updating kernel" | |
fi | |
if [[ ${WANT_SYMVERS} -ne 0 ]]; then | |
if [[ -f "${FW_REPOLOCAL}/Module.symvers" ]]; then | |
cp "${FW_REPOLOCAL}/Module.symvers" "${FW_PATH}/" | |
fi | |
if [[ -f "${FW_REPOLOCAL}/Module7.symvers" ]]; then | |
cp "${FW_REPOLOCAL}/Module7.symvers" "${FW_PATH}/" | |
fi | |
if [[ -f "${FW_REPOLOCAL}/git_hash" ]]; then | |
cp "${FW_REPOLOCAL}/git_hash" "${FW_PATH}/" | |
fi | |
fi | |
} | |
function finalise { | |
if [[ -f "${FW_PATH}/arm192_start.elf" ]]; then | |
echo " *** Setting 192M ARM split" | |
cp "${FW_PATH}/arm192_start.elf" "${FW_PATH}/start.elf" | |
fi | |
if [[ -e ${ROOT_PATH}/etc ]]; then | |
echo " *** Running ldconfig" | |
ldconfig -r "${ROOT_PATH}" | |
fi | |
echo " *** Storing current firmware revision" | |
echo "${FW_REV}" > "${FW_REVFILE}" | |
} | |
function do_backup { | |
if [[ ${SKIP_BACKUP} -eq 0 ]]; then | |
echo " *** Backing up files (this will take a few minutes)" | |
if [[ -d "${FW_PATH}.bak" ]]; then | |
echo " *** Remove old firmware backup" | |
rm -rf "${FW_PATH}.bak" | |
fi | |
echo " *** Backing up firmware" | |
cp -a "${FW_PATH}" "${FW_PATH}.bak" | |
if [[ ${SKIP_KERNEL} -eq 0 ]]; then | |
if [[ -d "${FW_MODPATH}.bak" ]]; then | |
echo " *** Remove old modules backup" | |
rm -rf "${FW_MODPATH}.bak" | |
fi | |
echo " *** Backing up modules $(uname -r)" | |
if [[ -d "${FW_MODPATH}/$(uname -r)" ]]; then | |
mkdir -p "${FW_MODPATH}.bak" && cp -a "${FW_MODPATH}/$(uname -r)" "${FW_MODPATH}.bak" | |
fi | |
fi | |
fi | |
} | |
function do_update { | |
show_notice | |
download_rev | |
if [[ -f "${FW_REPOLOCAL}/pre-install" ]]; then | |
echo " *** Running pre-install script" | |
source "${FW_REPOLOCAL}/pre-install" | |
fi | |
update_firmware | |
update_modules | |
update_vc_libs | |
update_sdk | |
finalise | |
if [[ -f "${FW_REPOLOCAL}/post-install" ]]; then | |
echo " *** Running post-install script" | |
source "${FW_REPOLOCAL}/post-install" | |
fi | |
remove_rev | |
echo " *** Syncing changes to disk" | |
sync | |
echo " *** If no errors appeared, your firmware was successfully updated to ${FW_REV}" | |
if [[ "${ROOT_PATH}" == "/" ]]; then | |
echo " *** A reboot is needed to activate the new firmware" | |
fi | |
} | |
function download_rev { | |
if [[ ${SKIP_DOWNLOAD} -eq 0 ]]; then | |
if ! eval curl -Lfs ${GITHUB_AUTH_PARAM} --output /dev/null --head --fail "${REPO_URI}/tarball/${FW_REV}"; then | |
echo "Invalid git hash specified" | |
exit 1 | |
fi | |
echo " *** Downloading specific firmware revision (this will take a few minutes)" | |
rm -rf "${FW_REPOLOCAL}" | |
mkdir -p "${FW_REPOLOCAL}" | |
eval curl -L ${GITHUB_AUTH_PARAM} "${REPO_URI}/tarball/${FW_REV}" | tar xzf - -C "${FW_REPOLOCAL}" --strip-components=1 | |
fi | |
} | |
function remove_rev { | |
echo " *** Deleting downloaded files" | |
if [[ ${SKIP_REPODELETE} -eq 0 ]]; then | |
rm -rf "${FW_REPOLOCAL}" | |
fi | |
} | |
function noobs_fix { | |
echo " !!! $BOOT_PATH appears to contain NOOBS files" | |
echo " This may occur if fstab contains incorrect entries." | |
echo " rpi-update will attempt to correct fstab." | |
read -p "Would you like to proceed? (y/N)" -n 1 -r -s | |
echo | |
if ! [[ $REPLY =~ ^[Yy]$ ]]; then | |
exit 1; | |
fi | |
if ! grep -qE "/dev/mmcblk0p1\s+/boot" ${ROOT_PATH}/etc/fstab; then | |
echo "Unexpected fstab entry" | |
exit 1 | |
fi | |
local ROOTNUM=`cat /proc/cmdline | sed -n 's|.*root=/dev/mmcblk0p\([0-9]*\).*|\1|p'` | |
if [ ! "$ROOTNUM" ];then | |
echo "Could not determine root partition." | |
exit 1 | |
fi | |
local BOOT_DEV="/dev/mmcblk0p$((ROOTNUM-1))" | |
local ROOT_DEV="/dev/mmcblk0p${ROOTNUM}" | |
sed ${ROOT_PATH}/etc/fstab -e "s|^.*[^#].* / |${ROOT_DEV} / |;s|^.*[^#].* /boot |${BOOT_DEV} /boot |" | |
read -p "Does this look correct? (y/N)" -n 1 -r -s | |
echo | |
if ! [[ $REPLY =~ ^[Yy]$ ]]; then | |
exit 1; | |
fi | |
sed ${ROOT_PATH}/etc/fstab -i -e "s|^.*[^#].* / |${ROOT_DEV} / |;s|^.*[^#].* /boot |${BOOT_DEV} /boot |" | |
umount /boot | |
if [ $? -ne 0 ]; then | |
echo "Failed to umount /boot. Remount manually and try again." | |
exit 1 | |
else | |
mount /boot | |
fi | |
} | |
function get_hash_date { | |
commit_api="https://api.github.com/repos/Hexxeh/rpi-firmware/git/commits/" | |
eval curl -Ls ${GITHUB_AUTH_PARAM} "$commit_api"$1 | grep "date" | head -1 | awk -F\" '{print $4}' | |
} | |
function compare_hashes { | |
date1=$(get_hash_date $1) | |
date2=$(get_hash_date $3) | |
if [ $(date -d "$date1" +%s) -$2 $(date -d "$date2" +%s) ]; then | |
echo true | |
else | |
echo false | |
fi | |
} | |
if [[ ${EUID} -ne 0 ]]; then | |
echo " !!! This tool must be run as root" | |
exit 1 | |
fi | |
echo " *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom" | |
if [[ ! -d ${WORK_PATH} ]]; then | |
echo " !!! ${WORK_PATH} doesn't exist - creating" | |
mkdir -p ${WORK_PATH} | |
fi | |
if [[ ${UPDATE_SELF} -ne 0 ]]; then | |
update_self | |
fi | |
if [[ ! -d "${FW_PATH}" ]]; then | |
echo " !!! ${FW_PATH} doesn't exist - creating" | |
mkdir -p ${FW_PATH} | |
fi | |
if [[ ${SKIP_KERNEL} -eq 0 ]] && [[ ! -d "${FW_MODPATH}" ]]; then | |
echo " !!! ${FW_MODPATH} doesn't exist - creating" | |
mkdir -p ${FW_MODPATH} | |
fi | |
if [[ ${NOOBS_CHECK} -eq 1 ]] && [[ -f ${BOOT_PATH}/recovery.elf ]]; then | |
noobs_fix | |
fi | |
command -v readelf >/dev/null 2>&1 || { | |
echo " !!! This tool requires you have readelf installed, please install it first" | |
echo " In Debian, try: sudo apt-get install binutils" | |
echo " In Arch, try: pacman -S binutils" | |
exit 1 | |
} | |
if [[ "${FW_REV}" == "" ]]; then | |
# ask github for latest version hash | |
REPO_API=${REPO_URI/github.com/api.github.com\/repos}/git/refs/heads/${BRANCH} | |
FW_REV=$(eval curl -Ls ${GITHUB_AUTH_PARAM} ${REPO_API} | awk '{ if ($1 == "\"sha\":") { print substr($2, 2, 40) } }') | |
if [[ "${FW_REV}" == "" ]]; then | |
echo " *** No hash received from github: ${REPO_API}" | |
# run again with errors not suppressed | |
eval curl -L ${GITHUB_AUTH_PARAM} ${REPO_API} | |
exit 1 | |
fi | |
fi | |
if [[ ! -f "${FW_REVFILE}" ]]; then | |
echo " *** We're running for the first time" | |
if [[ ${JUST_CHECK} -ne 0 ]]; then | |
echo "=================== 1" | |
exit 2 | |
fi | |
echo "=================== 2" | |
do_backup | |
echo "=================== 3" | |
else | |
if [[ $(cat "${FW_REVFILE}") == "${FW_REV}" ]]; then | |
echo " *** Your firmware is already up to date" | |
exit 0 | |
fi | |
if [[ ${JUST_CHECK} -ne 0 ]]; then | |
echo " *** Firmware update required. New commits available:" | |
DIFF_API=${REPO_URI/github.com/api.github.com\/repos}/compare/$(cat "${FW_REVFILE}")...${BRANCH} | |
SEPARATOR="======================================================" | |
eval curl -Ls ${GITHUB_AUTH_PARAM} ${DIFF_API} | awk -v SEPARATOR="${SEPARATOR}" -F\" ' { if ($2 == "commits") {commits=1} if (commits && $2 == "message") {print SEPARATOR "\nCommit: " $4} }' | sed 's/\\n\\n/\nCommit:\ /g' | |
exit 2 | |
fi | |
fi | |
echo "=================== 4" | |
do_update | |
echo "=================== 5" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment