Permalink
Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign uprpi-update/rpi-update
Go to file* always set user-agent for api.github.com requests This makes the updater work in environments where user agent is disabled via `.curlrc` (or similar means), which would otherwise run into an `Invalid hash given` error. Ref: https://developer.github.com/v3/#user-agent-required * move `-A curl` to a variable
| #!/bin/bash | |
| set -o nounset | |
| set -o errexit | |
| REPO_URI=${REPO_URI:-"https://github.com/Hexxeh/rpi-firmware"} | |
| REPO_API_URI=${REPO_URI/github.com/api.github.com\/repos} | |
| REPO_CONTENT_URI=${REPO_URI/github.com/raw.githubusercontent.com} | |
| UPDATE_SELF=${UPDATE_SELF:-1} | |
| UPDATE_REPO_URI="https://github.com/Hexxeh/rpi-update" | |
| UPDATE_REPO_CONTENT_URI=${UPDATE_REPO_URI/github.com/raw.githubusercontent.com} | |
| UPDATE_URI="${UPDATE_REPO_CONTENT_URI}/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:-"/"} | |
| CUR_FW_SUBDIR="/$(echo =$(vcgencmd get_config os_prefix) | cut -d'=' -f3)" | |
| FW_SUBDIR=${FW_SUBDIR:-${CUR_FW_SUBDIR}} | |
| if [[ "${FW_SUBDIR}" != "" ]]; then | |
| if [[ "${FW_SUBDIR::1}" != "/" ]]; then | |
| FW_SUBDIR="/$FW_SUBDIR" | |
| fi | |
| if [[ "${FW_SUBDIR: -1}" == "/" ]]; then | |
| FW_SUBDIR=${FW_SUBDIR: : -1} | |
| fi | |
| fi | |
| BOOT_PATH=${BOOT_PATH:-"/boot"} | |
| WORK_PATH=${WORK_PATH:-"${ROOT_PATH}/root"} | |
| SKIP_KERNEL=${SKIP_KERNEL:-0} | |
| SKIP_SDK=${SKIP_SDK:-0} | |
| SKIP_VCLIBS=${SKIP_VCLIBS:-0} | |
| SKIP_REPODELETE=${SKIP_REPODELETE:-0} | |
| SKIP_BACKUP=${SKIP_BACKUP:-0} | |
| SKIP_DOWNLOAD=${SKIP_DOWNLOAD:-0} | |
| SKIP_WARNING=${SKIP_WARNING:-0} | |
| SKIP_CHECK_PARTITION=${SKIP_CHECK_PARTITION:-0} | |
| WANT_SYMVERS=${WANT_SYMVERS:-0} | |
| WANT_PI4=${WANT_PI4:-0} | |
| PRUNE_MODULES=${PRUNE_MODULES:-0} | |
| RPI_UPDATE_UNSUPPORTED=${RPI_UPDATE_UNSUPPORTED:-0} | |
| JUST_CHECK=${JUST_CHECK:-0} | |
| RPI_REBOOT=${RPI_REBOOT:-0} | |
| CURL_OPTIONS=${CURL_OPTIONS:-""} | |
| GITHUB_API_TOKEN=${GITHUB_API_TOKEN:-""} | |
| FW_REPO="${REPO_URI}.git" | |
| FW_REPOLOCAL=${FW_REPOLOCAL:-"${WORK_PATH}/.rpi-firmware"} | |
| FW_PATH="${BOOT_PATH}${FW_SUBDIR}" | |
| FW_MODPATH="${ROOT_PATH}/lib/modules" | |
| FW_REV_IN=${1:-""} | |
| FW_REVFILE="${FW_PATH}/.firmware_revision" | |
| SELFUPDATE_SCRIPT="${WORK_PATH}/.updateScript.sh" | |
| [ "${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 | |
| # Always follow redirects | |
| CURL_OPTIONS="${CURL_OPTIONS} -L" | |
| # api.github.com requires a User-Agent header | |
| CURL_OPTIONS_API="${CURL_OPTIONS_API:-"-A curl"}" | |
| # Support for custom GitHub Auth Tokens | |
| if [[ -n "${GITHUB_API_TOKEN}" ]]; then | |
| echo " *** Using GitHub token for all requests." | |
| CURL_OPTIONS="${CURL_OPTIONS} --header \"Authorization: token ${GITHUB_API_TOKEN}\"" | |
| fi | |
| GITHUB_API_LIMITED=$(eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "https://api.github.com/rate_limit" | tr -d "," | awk 'BEGIN {reset=0;} { if ($1 == "\"limit\":") limit=$2; else if ($1 == "\"remaining\":") remaining=$2; else if ($1 == "\"reset\":" && limit>0 && remaining==0) reset=$2;} END { print reset }') | |
| if [ ${GITHUB_API_LIMITED} -gt 0 ]; then | |
| echo " *** Github API is currently rate limited - please try again after $(date --date @${GITHUB_API_LIMITED})" | |
| exit 1 | |
| fi | |
| function update_self() { | |
| echo " *** Performing self-update" | |
| local _tempFileName="$0.tmp" | |
| if ! eval curl -fs ${CURL_OPTIONS} --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 | |
| if [[ "$(head -1 ${_tempFileName})" != '#!/bin/bash' ]]; then | |
| echo " !!! Failed to download update for rpi-update!" | |
| echo " !!! Contents of file is not as expected - github may be down" | |
| exit 1 | |
| fi | |
| local 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 > "${SELFUPDATE_SCRIPT}" << EOF | |
| if mv "${_tempFileName}" "$0"; then | |
| rm -- "\$0" | |
| exec env UPDATE_SELF=0 /bin/bash "$0" "${FW_REV_IN}" | |
| else | |
| echo " !!! Failed!" | |
| fi | |
| EOF | |
| echo " *** Relaunching after update" | |
| exec /bin/bash "${SELFUPDATE_SCRIPT}" | |
| } | |
| 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 | |
| find "${FW_REPOLOCAL}/modules" -mindepth 1 -maxdepth 1 -type d | while read DIR; do | |
| BASEDIR="$(basename "${DIR}")" | |
| if [[ ${WANT_PI4} -ne 1 ]]; then | |
| ENDSWITH=${BASEDIR: -4} | |
| if [[ "${ENDSWITH}" == "v7l+" ]]; then | |
| continue; | |
| fi | |
| ENDSWITH=${BASEDIR: -3} | |
| if [[ "${ENDSWITH}" == "v8+" ]]; then | |
| continue; | |
| fi | |
| fi | |
| cp -R "${DIR}" "${FW_MODPATH}/" | |
| echo " *** depmod ${BASEDIR}" | |
| depmod -b "${ROOT_PATH}" -a "${BASEDIR}" | |
| done | |
| else | |
| echo " *** As requested, not updating kernel modules" | |
| fi | |
| } | |
| function update_vc_libs { | |
| if [[ ${SKIP_VCLIBS} -eq 0 ]]; then | |
| echo " *** Updating VideoCore libraries" | |
| else | |
| echo " *** As requested, not updating VideoCore libraries" | |
| return | |
| fi | |
| if [[ -e ${ROOT_PATH}/bin/sh ]]; then | |
| local ELFOUTPUT=$(readelf -a "${ROOT_PATH}/bin/sh"; readelf -h "${ROOT_PATH}/bin/sh") | |
| else | |
| local 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 | |
| } | |
| # Check if the bootloader is older than the latest critical release. An old | |
| # bootloader shouldn't block rpi-update so just inform the user that bootloader | |
| # is out of date. | |
| function check_eeprom_version { | |
| local CURRENT_VERSION="" | |
| local FIRST_VERSION=1557513636 | |
| # MIN VERSION for Sep 10 2019 EEPROM | |
| local MIN_VERSION=1568112110 | |
| local HAVE_BOOTLOADER_EEPROM=0 | |
| # Skip EEPROM check if vcgencmd is missing because it won't be possible to | |
| # check the version. | |
| if ! command -v vcgencmd > /dev/null; then | |
| return | |
| fi | |
| rev="$(sed -n '/^Revision/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo)" | |
| if [ $(((0x$rev >> 23) & 1)) -ne 0 ] && [ $(((0x$rev >> 12) & 15)) -eq 3 ]; then | |
| HAVE_BOOTLOADER_EEPROM=1 | |
| fi | |
| if [ "${HAVE_BOOTLOADER_EEPROM}" != 1 ]; then | |
| return | |
| fi | |
| # vcgencmd doesn't return non-zero for unknown commands. | |
| if vcgencmd bootloader_config | grep -qi "Command not registered"; then | |
| # Firmware is too old to return the bootloader config | |
| return | |
| fi | |
| # If FREEZE_VERSION is specified then assume that the user doesn't want | |
| # an EEPROM update so skip the check. | |
| if vcgencmd bootloader_config | grep -q FREEZE_VERSION=1; then | |
| return | |
| fi | |
| if vcgencmd bootloader_version | grep -q timestamp; then | |
| CURRENT_VERSION=$(vcgencmd bootloader_version | grep timestamp | awk '{print $2}') | |
| if [ "${CURRENT_VERSION}" = "0" ]; then | |
| # If a timestamp of zero is returned then it's new firmware but an | |
| # old bootloader. Assume bootloader v0 | |
| CURRENT_VERSION="${FIRST_VERSION}" | |
| fi | |
| elif vcgencmd bootloader_version | grep -qi "unknown"; then | |
| return | |
| else | |
| # New bootloader / old firmware ? Try to parse the date | |
| CURRENT_VERSION=$(date -u +%s --date "$(vcgencmd bootloader_version | head -n1)") | |
| fi | |
| # Failed to parse the version. Default to the initial production release. | |
| if [ -z "${CURRENT_VERSION}" ]; then | |
| CURRENT_VERSION="${FIRST_VERSION}" | |
| fi | |
| if [ "${CURRENT_VERSION}" -lt "${MIN_VERSION}" ]; then | |
| echo "A newer bootloader EEPROM version is available." | |
| echo "On Debian, try: sudo apt update; sudo apt install rpi-eeprom" | |
| echo "then reboot to install the new bootloader" | |
| fi | |
| } | |
| function show_notice { | |
| local NOTICE_URI=${REPO_CONTENT_URI}/${FW_REV}/NOTICE.md | |
| local FULL_NOTICE=$(eval curl -fs ${CURL_OPTIONS} "${NOTICE_URI}") | |
| if [ -z "${FULL_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 ${NOTICE_HASH_EXISTS}; then | |
| local NOTICE=$(echo "${FULL_NOTICE}" | tail -n+2) | |
| 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 | |
| else | |
| local NOTICE=${FULL_NOTICE} | |
| 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 check_partition { | |
| if [[ ${SKIP_CHECK_PARTITION} -ne 0 ]]; then | |
| return | |
| fi | |
| local PARTSIZE=0 | |
| if command -v df > /dev/null 2>&1 ; then | |
| local M=$(df -P ${BOOT_PATH} | awk 'END{print $1}') | |
| if [[ $M == /dev/* ]]; then | |
| if command -v lsblk > /dev/null 2>&1 ; then | |
| PARTSIZE=$(lsblk -bno SIZE ${M}) | |
| fi | |
| fi | |
| fi | |
| if [ $PARTSIZE -ne 0 ] && [ $PARTSIZE -lt $(( 256*1024*1024 )) ]; then | |
| echo "Partition size $(( $PARTSIZE >> 20 ))M may not be sufficient for new Pi4 files" | |
| echo "This could result in a system that will not boot." | |
| echo "256M FAT partition is recommended. Ensure you have a backup if continuing." | |
| 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 | |
| fi | |
| } | |
| function update_firmware { | |
| echo " *** Updating firmware" | |
| rm -rf "${FW_PATH}/"*.elf | |
| rm -rf "${FW_PATH}/"bootcode.bin | |
| if [[ ${WANT_PI4} -eq 1 ]]; then | |
| cp "${FW_REPOLOCAL}/"*.elf "${FW_PATH}/" | |
| cp "${FW_REPOLOCAL}/"*.dat "${FW_PATH}/" | |
| else | |
| cp "${FW_REPOLOCAL}/"start{,[^4]*}.elf "${FW_PATH}/" | |
| cp "${FW_REPOLOCAL}/"fixup{,[^4]*}.dat "${FW_PATH}/" | |
| fi | |
| cp "${FW_REPOLOCAL}/"*.bin "${FW_PATH}/" | |
| if [[ ${SKIP_KERNEL} -eq 0 ]]; then | |
| if [[ ${WANT_PI4} -eq 1 ]]; then | |
| cp "${FW_REPOLOCAL}/"*.img "${FW_PATH}/" | |
| else | |
| cp "${FW_REPOLOCAL}/"kernel.img "${FW_REPOLOCAL}/"kernel7.img "${FW_PATH}/" | |
| fi | |
| 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)" | |
| local OLD_FW_PATH="${BOOT_PATH}.bak" | |
| if [[ -d "${OLD_FW_PATH}" ]]; then | |
| echo " *** Remove old firmware backup" | |
| rm -rf "${OLD_FW_PATH}" | |
| fi | |
| echo " *** Backing up firmware" | |
| cp -a "${FW_PATH}" "${OLD_FW_PATH}" | |
| if [[ ${SKIP_KERNEL} -eq 0 ]]; then | |
| OLD_FW_MODPATH=${FW_MODPATH}.bak | |
| if [[ -d "${OLD_FW_MODPATH}" ]]; then | |
| echo " *** Remove old modules backup" | |
| rm -rf "${OLD_FW_MODPATH}" | |
| fi | |
| echo " *** Backing up modules $(uname -r)" | |
| local CURRENT_FW_MODPATH=${FW_MODPATH}/$(uname -r) | |
| if [[ -d "${CURRENT_FW_MODPATH}" ]]; then | |
| mkdir -p "${OLD_FW_MODPATH}" && cp -a "${CURRENT_FW_MODPATH}" "${OLD_FW_MODPATH}" | |
| fi | |
| fi | |
| fi | |
| } | |
| function do_update { | |
| if [ -f ${FW_PATH}/kernel7l.img ]; then | |
| WANT_PI4=1 | |
| fi | |
| if [[ ${WANT_PI4} -eq 1 ]]; then | |
| check_partition | |
| fi | |
| check_eeprom_version | |
| 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 | |
| if [[ ${RPI_REBOOT} -ne 0 ]]; then | |
| echo " *** Rebooting to activate the new firmware" | |
| reboot | |
| else | |
| echo " *** A reboot is needed to activate the new firmware" | |
| fi | |
| fi | |
| } | |
| function download_rev { | |
| if [[ ${SKIP_DOWNLOAD} -eq 0 ]]; then | |
| local FW_TARBALL_URI=${REPO_URI}/tarball/${FW_REV} | |
| if ! eval curl -fs ${CURL_OPTIONS} --output /dev/null --head "${FW_TARBALL_URI}"; 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 ${CURL_OPTIONS} "${FW_TARBALL_URI}" | 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_PATH}" | |
| if [ $? -ne 0 ]; then | |
| echo "Failed to umount ${BOOT_PATH}. Remount manually and try again." | |
| exit 1 | |
| else | |
| mount "/boot" | |
| fi | |
| } | |
| function get_hash_date { | |
| local COMMITS_URI=${REPO_API_URI}/commits/$1 | |
| eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${COMMITS_URI}" | grep "date" | head -1 | awk -F\" '{print $4}' | |
| } | |
| function compare_hashes { | |
| local DATE1=$(get_hash_date "$1") | |
| local DATE2=$(get_hash_date "$3") | |
| if [ $(date -d "${DATE1}" +%s) -$2 $(date -d "${DATE2}" +%s) ]; then | |
| echo true | |
| else | |
| echo false | |
| fi | |
| } | |
| function get_long_hash { | |
| # ask github for long version hash | |
| local COMMITS_URI=${REPO_API_URI}/commits/$1 | |
| eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${COMMITS_URI}" | awk 'BEGIN {hash=""} { if (hash == "" && $1 == "\"sha\":") {hash=substr($2, 2, 40);} } END {print hash}' | |
| } | |
| 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 | |
| else | |
| rm -f "${SELFUPDATE_SCRIPT}" | |
| 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_IN}" == "" ]]; then | |
| FW_REV_IN=${BRANCH} | |
| fi | |
| FW_REV=$(get_long_hash "${FW_REV_IN}") | |
| if [[ "${FW_REV}" == "" ]]; then | |
| echo " *** Invalid hash given" | |
| exit 1 | |
| fi | |
| if [[ ! -f "${FW_REVFILE}" ]]; then | |
| LOCAL_HASH=0 | |
| echo " *** We're running for the first time" | |
| if [[ ${JUST_CHECK} -ne 0 ]]; then | |
| echo " *** Firmware update required. No local hash to compare to." | |
| exit 2 | |
| fi | |
| do_backup | |
| else | |
| LOCAL_HASH=$(get_long_hash "$(cat "${FW_REVFILE}")") | |
| if [[ "${LOCAL_HASH}" == "${FW_REV}" ]]; then | |
| echo " *** Your firmware is already up to date" | |
| exit 0 | |
| fi | |
| if [[ ${JUST_CHECK} -ne 0 ]]; then | |
| if $(compare_hashes "${LOCAL_HASH}" lt "${FW_REV}"); then | |
| echo " *** Firmware update required. New commits available:" | |
| DIFF_URI=${REPO_API_URI}/compare/${LOCAL_HASH}...${FW_REV} | |
| else | |
| echo " *** Firmware downgrade requested. Commits to drop:" | |
| DIFF_URI=${REPO_API_URI}/compare/${FW_REV}...${LOCAL_HASH} | |
| fi | |
| SEPARATOR="======================================================" | |
| eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${DIFF_URI}" | 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 | |
| do_update |