#!/bin/bash set -o nounset set -o errexit REPO_URI=${REPO_URI:-"https://github.com/raspberrypi/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/raspberrypi/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= if [ -f /proc/cpuinfo ]; then rev="$(sed -n '/^Revision/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo)" fi if [ -n $rev ] && [ $(((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 ] || [ -f ${FW_PATH}/kernel8.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 (delete ${FW_REVFILE} to force an update anyway)" 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