#!/bin/bash

# This is a hook for the updater that is run on init, download, update
# and postupdate
# It currently does:
# -  On 'init' reports the currently installed firmware on stdout.
# -  On 'init' generates the list of "external" packages, if it does not yet exist.
# -  On 'download' make as much free space as possible available,
#    by removing the old / large logs
# -  On 'update' fixup possibly broken /etc/resolv.conf symlink.
# -  On 'update' stop the player and put the update splash screen
# -  On 'update' and 'postupdate' remove all leftover locale files
#    and doc files on non-devel systems, just in case
# -  On 'postupdate' signal to keep the boot log on next boot.
# -  On 'postupdate' add a compatibility initctl pipe link if needed.
# -  On 'postupdate' process all configured removals.
# -  On 'postupdate' remove old kernels and restore possible removed kernel image link
# -  On 'postupdate' search for and recover any .rpmsave files.
# -  On 'postupdate' repair any broken alternatives of update-alternatives.
# -  On 'postupdate' removes the list of "external" packages if it exists.

ACTION="$1"
CALLER_VERSION="$2"
VERSION="1.17"
EXTERNALXML=/var/run/updater/external.xml
MOVEDFILESDIR=/var/cache/updater/moved-files

HWINFOLOADED=
inithwinfo() {
    RECOVERYIMGBDEV1=
    RECOVERYIMGBDEV2=
    RECOVERYIMGTYPE=

    [ -z "$HWINFOLOADED" ] || return 0
    HWINFOLOADED=1

    [ -f /etc/spinetix/identifiers ] && . /etc/spinetix/identifiers

    case "$SPX_HW_TYPE" in
        ikebana)
            RECOVERYIMGBDEV1=/dev/"$SPX_MAIN_DISK_NAME"gp0
            RECOVERYIMGBDEV2=/dev/"$SPX_MAIN_DISK_NAME"gp1
            RECOVERYIMGTYPE=mkimage
            ;;
        fukiran|ume|tsubaki|"DSOS|"*)
            if [[ "$SPX_MAIN_DISK_NAME" =~ [0-9]$ ]] ; then
                RECOVERYIMGBDEV1=/dev/"$SPX_MAIN_DISK_NAME"p4
                RECOVERYIMGBDEV2=/dev/"$SPX_MAIN_DISK_NAME"p5
            else
                RECOVERYIMGBDEV1=/dev/"$SPX_MAIN_DISK_NAME"4
                RECOVERYIMGBDEV2=/dev/"$SPX_MAIN_DISK_NAME"5
            fi
            RECOVERYIMGTYPE=squashfs
            ;;
        *)
            echo "ERROR: unknown hardware type '$SPX_HW_TYPE'" >&2
            return 1
            ;;
    esac
}

# returns the version of the recovery image at the given location
# it returns the value "0" if corrupted, so that an upgrade would be forced
# return code is non-zero if image does not exist or type is unknown
get_recovery_version() {
    local img="$1"
    local tmpdir ver maxkb

    case "$RECOVERYIMGTYPE" in
        squashfs)
            if [ ! -e "$img" ]; then
                echo "ERROR: recovery image '$img' does not exist" >&2
                return 1
            fi
            tmpdir=$(mktemp -d) || return 1
            if ! unsquashfs -d "$tmpdir"/out "$img" > /dev/null; then
                echo "WARNING: corrupted recovery image '$img', failed decompress" >&2
                echo 0
            elif ! [ -f "$tmpdir"/out/bootimgs.sha256sum ] || ! (cd "$tmpdir"/out && sha256sum -c --quiet bootimgs.sha256sum); then
                echo "WARNING: corrupted recovery image '$img', failed checksums" >&2
                echo 0
            elif ! [ -f "$tmpdir"/out/os-release ]; then
                echo "WARNING: corrupted recovery image '$img', missing os-release" >&2
                echo 0
            else
                ver=$(sed -n -e '/VERSION_ID=/{s/^[^=]*=//;s/^['\''\"]//;s/['\''\"][[:space:]]*$//;p;}' "$tmpdir"/out/os-release)
                if [ -z "$ver" ]; then
                    echo "WARNING: corrupted recovery image '$img', no version in os-release" >&2
                    echo 0
                else
                    echo "$ver"
                fi
            fi
            rm -rf "$tmpdir"
            ;;
        mkimage)
            if [ ! -e "$img" ]; then
                echo "ERROR: recovery image '$img' does not exist" >&2
                return 1
            fi
            tmpdir=$(mktemp -d) || return 1
            # we impose a count just in case the partition is
            # oversized, we use 16k block size for performance and
            # future compatibility with large logical sector devices
            maxkb="$((64*1024))"
            # NOTE: dd always outputs some status to stderr, so redirect it to
            # a temporary file and output its stderr only if dd fails.
            dd bs=16k if="$1" of="$tmpdir"/umulti.bin count="$(( (maxkb + 15) / 16 ))" status=noxfer 2>"$tmpdir"/errlog
            if [ $? -ne 0 ]; then
                cat "$tmpdir"/errlog >&2
                echo "ERROR: failed to read from recovery image '$img'" >&2
                rm -rf "$tmpdir"
                return 1
            elif ! dumpimage -T multi -p 1 -o "$tmpdir"/reco.cpio.gz "$tmpdir"/umulti.bin; then
                echo "WARNING: corrupted recovery image '$img', failed image extraction" >&2
                echo 0
            elif ! rm -f "$tmpdir"/umulti.bin || ! gunzip "$tmpdir"/reco.cpio.gz; then
                echo "WARNING: corrupted recovery image '$img', failed decompression" >&2
                echo 0
            elif ! (mkdir "$tmpdir"/out && cd "$tmpdir"/out && cpio -id --quiet '*/os-release' < "$tmpdir"/reco.cpio); then
                echo "WARNING: corrupted recovery image '$img', failed archive extraction" >&2
                echo 0
            elif ! [ -f "$tmpdir"/out/etc/os-release ]; then
                echo "WARNING: corrupted recovery image '$img', missing os-release" >&2
                echo 0
            else
                ver=$(sed -n -e '/^[[:space:]]*VERSION_ID=/{s/^[^=]*=//;s/^['\''\"]//;s/['\''\"][[:space:]]*$//;p;q;}' "$tmpdir"/out/etc/os-release)
                if [ -z "$ver" ]; then
                    echo "WARNING: corrupted recovery image '$img', no version in os-release" >&2
                    echo 0
                else
                    echo "$ver"
                fi
            fi
            rm -rf "$tmpdir"
            ;;
        *)
            echo "ERROR: unknown recovery image type '$RECOVERYIMGTYPE'" >&2
            return 1
            ;;
    esac
}

# returns the version of the currently running firmware
# if no firmware version is found it returns with an error code
get_firmware_version() {
    local ver="$(sed -n -e '/^[[:space:]]*VERSION_ID=/{s/^[^=]*=//;s/^['\''\"]//;s/['\''\"][[:space:]]*$//;p;q;}' /etc/os-release)"
    if [ -z "$ver" ]; then
        echo "WARNING: could not find version of running firmware" >&2
        return 1
    else
        echo "$ver"
    fi
}

escape_xml_markup() {
    sed -e 's,&,\&amp;,g; s,<,\&lt;,g; s,>,\&gt;,g; s,",\&quot;,g; s,'\'',\&apos;,g'
}

# outputs the package element for a flashed firmware
# arg1: name
# arg2: arch
# arg3: version
# arg4: release
# [arg5..argN]: dependency type, name, sense (e.g., EQ, GT, GE), version, release
# A dash and all following characters are removed from all version and release strings
output_flashedfw_package_xml() {
    local name="$(echo "$1" | escape_xml_markup)"
    local arch="$(echo "$2" | escape_xml_markup)"
    local version="$(echo "${3%%-*}" | escape_xml_markup)"
    local release="$(echo "${4%%-*}" | escape_xml_markup)"
    shift 4

cat <<EOF
<package type="flashedfw">
  <name>$name</name>
  <arch>$arch</arch>
  <version epoch="0" ver="$version" rel="$release"/>
  <format>
EOF
    while [ $# -ge 5 ]; do
cat <<EOF
    <spx:$1>
      <spx:entry name='$2' flags='$3' epoch='0' ver='${4%%-*}' rel='${5%%-*}'/>
    </spx:$1>
EOF
    shift 5
    done
cat <<EOF
  </format>
</package>
EOF
}

generate_external_xml() {
    local header footer tmpxml
    local version

    inithwinfo || return 1
    . /usr/share/resources/default/init/main || return 1

header=$(cat <<\EOF
<?xml version="1.0" encoding="UTF-8"?>
<metadata xmlns="http://linux.duke.edu/metadata/common" xmlns:spx="http://spinetix.com/metadata/spx">
EOF
)

footer=$(cat <<\EOF
</metadata>
EOF
)

    tmpxml="$(mktemp "$EXTERNALXML".XXXXXX)" || return 1
    echo "$header" > "$tmpxml"
    if [ -n "$RECOVERYIMGBDEV1" ]; then
        version="$(get_recovery_version "$RECOVERYIMGBDEV1")" && \
            output_flashedfw_package_xml recovery-"${rc_vendor,,}"-"${rc_model,,}"-main "$rc_macharch" "$version" 0 \
            provides recovery-"${rc_vendor,,}"-"${rc_model,,}"-main "EQ" "$version" 0 \
            provides recovery-"${rc_vendor,,}"-"${rc_model,,}"-main-installed "EQ" "$version" 0 >> "$tmpxml"
    fi
    if [ -n "$RECOVERYIMGBDEV2" ]; then
        version="$(get_recovery_version "$RECOVERYIMGBDEV2")" && \
            output_flashedfw_package_xml recovery-"${rc_vendor,,}"-"${rc_model,,}"-backup "$rc_macharch" "$version" 0 \
            provides recovery-"${rc_vendor,,}"-"${rc_model,,}"-backup "EQ" "$version" 0 \
            provides recovery-"${rc_vendor,,}"-"${rc_model,,}"-backup-installed "EQ" "$version" 0 >> "$tmpxml"
    fi
    version="$(get_firmware_version)" && \
            output_flashedfw_package_xml fw-"${rc_vendor,,}"-"${rc_model,,}"-running "$rc_macharch" "${version%%-*}" "${version#*-}" \
                provides fw-"${rc_vendor,,}"-"${rc_model,,}"-running "EQ" "${version%%-*}" "${version#*-}" \
                recommends fw-"${rc_vendor,,}"-"${rc_model,,}" "GT" "${version%%-*}" "${version#*-}" >> "$tmpxml"
    echo "$footer" >> "$tmpxml"
    mv -f "$tmpxml" "$EXTERNALXML"
}

clear_logs() {
    echo "clearing old / large logs"

    # Remove all log files of simple daemons which are rotated on each boot
    # and not handled by logrotate if they get large, they all have a simple
    # numeric suffix (the logrotate configuration compressed all old logs).
    find /var/log -type f -size +500k -name "*.[0-9]" -print0 | \
	xargs -0r rm -f --

    # Remove all compressed log files above 2 MiB
    find /var/log -type f -size +2M -name "*.gz" -print0 | \
	xargs -0r rm -f --

    # Truncate all log files above 10 MiB (logrotate uses 800 KiB as limit but
    # it runs only once a day, so recent activity can lead to much larger logs);
    # do not remove the files as they are anyways open elsewhere
    find /var/log -type f -size +10M -exec cp /dev/null \{\} \;
}

# Removes all locale language directories that may have been left around by
# mis-packaged RPMs which do not tag locale files with a language tag
remove_locale_files()
{
    [ -d /usr/share/locale/ ] && find /usr/share/locale/ -mindepth 1 -delete
}

# Removes all documentation files (not directories!)
remove_doc_files()
{
    for d in /usr/share/man /usr/share/doc /usr/share/info; do
	[ -d "$d" ] && find "$d" -type f -delete
    done
}

# Very large updates can fail due to lack of space in the root filesystem,
# this is temporary space needed while installing the packages, but
# immediately recovered at the end of rpm install, when the newly installed
# files are renamed over the old files. To overcome this known bulky files
# are moved to the /srv filesystem, replacing the originals by symlinks, and
# a restore script created. The restore script copies the files back to
# their original place, if they are still the expected symlink (meaning they
# were not replaced). The restore script then removes all the moved files,
# in all cases.
# The package which is very large and creates this issue is cef.
#
# arg1: max installed size in KiB
prepare_for_large_updates()
{
    local nr_available_blks blk_sz junk
    local update_size_kb="$1"
    local ret=0

    read nr_available_blks blk_sz junk < <(stat -f -c '%a %S' /)
    if [ $? -ne 0 -o -n "$junk" ]; then
        echo "failed getting available size on root filesystem" >&2
        return 1
    fi
    if [ $(( nr_available_blks / 10 * 8 )) -ge $(( update_size_kb / ( blk_sz / 1024 ) )) ]; then
        return 0
    fi

    echo "update needs more than 80% of available storage, moving bulky files to make room"

    if [ ! -f /usr/lib/cef/libcef.so ]; then
        echo "no bulky files to move"
        return 0
    fi

    mkdir "$MOVEDFILESDIR"
cat > "$MOVEDFILESDIR"/restore >> "$MOVEDFILESDIR"/restore <<EOF
#!/bin/sh

MOVEDFILESDIR=$MOVEDFILESDIR

EOF

    chmod +x "$MOVEDFILESDIR"/restore

cat >> "$MOVEDFILESDIR"/restore <<'EOF'
if [ -L /usr/lib/cef/libcef.so ]; then
    if [ "$(readlink /usr/lib/cef/libcef.so)" = "$MOVEDFILESDIR/libcef.so" ]; then
        [ -f "$MOVEDFILESDIR"/libcef.so ] && \
            cp -a "$MOVEDFILESDIR"/libcef.so /usr/lib/cef/libcef.so.restore && \
            sync && \
            mv /usr/lib/cef/libcef.so.restore /usr/lib/cef/libcef.so
    fi
fi

EOF

    cp -a /usr/lib/cef/libcef.so "$MOVEDFILESDIR" && \
        sync && \
        ln -sf "$MOVEDFILESDIR"/libcef.so /usr/lib/cef/libcef.so && \
        sync || \
        ret=1


cat >> "$MOVEDFILESDIR"/restore <<'EOF'
sync
rm -rf "$MOVEDFILESDIR"
EOF

    if [ $ret -ne 0 ]; then
        echo "failed moving files to make space for update" >&2
        "$MOVEDFILESDIR"/restore
    fi

    # give time for player to exit and free up the inodes of moved files
    sleep 5

    return $ret
}

# libc depends on a matching version of nscd, a mismatched nscd can
# result in name lookup failures with no fallback from libc; old firmware
# versions do not have dependencies to ensure that the two are in sync
# so detect a mismatch and replace nscd by a dummy to avoid lookup failures;
# the dummy will be replaced by the matching nscd when the firmware update
# is completed. As nscd is a cache the system can still run without it.
workaround_nscd_libc_desync()
{
    local libc6_ver nscd_ver

    libc6_ver="$(rpm -q --queryformat '%{VERSION}\n' libc6)"
    if [ $? -ne 0 -o -z "$libc6_ver" ]; then
        echo "failed to get installed libc version for nscd workaround check"
        return 1
    fi
    nscd_ver="$(rpm -q --queryformat '%{VERSION}\n' nscd)"
    if [ $? -ne 0 -o -z "$nscd_ver" ]; then
        echo "no nscd detected, no nscd workaround needed"
        return 1
    fi
    # if nscd and libc6 are in sync no workaround is needed
    if [ "$nscd_ver" = "$libc6_ver" ]; then
        return 0
    fi

    echo "the libc ($libc6_ver) is not the same version as nscd ($nscd_ver), replacing nscd by a dummy"
    cat > /usr/sbin/nscd.dummy <<'EOF'
#!/bin/bash

# dummy nscd "daemon"

pid="$(cat /run/nscd/nscd.pid 2>/dev/null)"

if [ "$1" = "-K" ]; then
    rm -f /run/nscd/nscd.pid
    if [ -n "$pid" ]; then
        kill $pid
        exit
    else
        exit 1
    fi
fi

if [ -n "$pid" ] && kill -0 $pid; then
    # already running, ignore all arguments and do nothing
    exit 0
fi

echo -n dummy nscd
(
trap '' SIGHUP
echo $BASHPID > /run/nscd/nscd.pid
while : ; do
    sleep 3600
done
) &
EOF

     chmod +x /usr/sbin/nscd.dummy
     mv /usr/sbin/nscd.dummy /usr/sbin/nscd
}

# Process package removals in /etc/updater/removals.d/*.conf files.
# These files contain list of packages to be removed, packages that
# are to be removed together should be in one line, use backslash to
# break long lines. Lines starting with # are ignored.
# Files are processed in sort order, from first line to last line.
process_removals()
{
    for f in /etc/updater/removals.d/*.conf; do
	[ -f "$f" ] || continue
	while read pkgset; do
	    # skip lines starting with # or whitespace only
	    [[ "$pkgset" =~ ^[[:space:]]*(#.*|[[:space:]]*)$ ]] && continue
	    # if packages in set are not all installed skip it
	    rpm --query --quiet $pkgset || continue
	    # attempt to remove the packages
	    echo "removing package set listed in ${f##*/}: $pkgset"
	    if rpm --erase --allmatches $pkgset; then
		echo "successfully removed"
	    else
		echo "removal failed, some packages still in use?"
	    fi
	done < "$f"
    done
}

# Removes all the older kernels and their modules, when kernel packages
# embed the kernel version in their name, so when a kernel with a different
# version is installed it is not a package update and thus older kernels
# are not automatically removed.
remove_old_kernels()
{
    local kpkgname=kernel
    local kimgtype=bzimage
    local kver

    # get the current kernel version
    kver="$(rpm -q --queryformat '%{VERSION}\n' $kpkgname)"
    if [ $? -ne 0 -o -z "$kver" -o "${kver/ /}" != "$kver" ]; then
        echo "no kernel installed"
        return
    fi

    # get packages that provide a kernel, whose name starts with $kpkgname
    # but are not the same version as the current kernel
    local name version
    local mainpkgs=
    while read name version; do
        [ "${name#$kpkgname}" != "$name" -a "$version" != "$kver" ] || continue
        mainpkgs="$mainpkgs${mainpkgs:+ }$name"
    done < <(rpm -q --queryformat '%{NAME} %{VERSION}\n' --whatprovides $kpkgname-image-$kimgtype $kpkgname-image $kpkgname-base)
    if [ -z "$mainpkgs" ]; then
        echo "no old kernel packages to remove"
        return
    fi

    # now get all the packages which require the packages to remove, they would be the kernel modules
    local extrapkgs="$(rpm -q --whatrequires $mainpkgs)"
    local allpkgs="$(echo $mainpkgs $extrapkgs | tr ' ' '\n' | sort -u)"
    local npkgs="$(echo $allpkgs | wc -w)"

    echo "removing $npkgs old kernel packages"

    rpm -e --allmatches $allpkgs
    if [ $? -eq 0 ]; then
        echo "packages removed successfully"
    else
        echo "failed removing, old kernel remains installed"
    fi
}

# Due to packaging problems with older kernels the /boot/bzImage
# symlink may be removed after old kernel packages are removed. If that
# is the case recreate the link, querying the kernel image package for
# the kernel image name.
restore_kimg_link()
{
    [ -e /boot/bzImage ] && return

    echo "Restoring /boot/bzImage link"
    # if there are multiple files starting with /boot/bzImage- use the shortest file name
    local kimg="$(rpm -ql --whatprovides kernel-image-bzimage | LC_ALL=C sort | grep -m 1 ^/boot/bzImage-)" || return
    if [ -z "$kimg" ]; then
        echo "Kernel image package does not include bzImage"
        return
    fi
    ln -sf "$(basename "$kimg")" /boot/bzImage
    if [ $? -eq 0 ]; then
        echo "restored"
    else
        echo "failed restoring, system may be unbootable"
    fi
}

# find any .rpmsave file, there should be none, warn about them and
# move them back to their base name.
recover_rpmsave()
{
    local sconf conf
    # we only process the root fs, other fs do not have config files
    find / -xdev -name "*.rpmsave" -print0 |
    while read -r -d $'\0' sconf; do
	conf="${sconf%.rpmsave}"
	if [ -f "$conf" ]; then
	    echo "warning: found stray .rpmsave for '$conf', recovering"
	    mv -f "$sconf" "$conf"
	else
	    echo "warning: found stray .rpmsave for non-existing '$conf'"
	fi
    done
}

stop_player() {
    local pidfile="/var/run/raperca.pid"
    [ -s "$pidfile" ] || return
    echo "stopping player"
    local pid="$(< "$pidfile")"
    # using a stop-nowait against our caller will just show
    # the splash screen immediately, instead of waiting for
    # the watchdog to do it for us a bit later
    /etc/init.d/updater stop-nowait
    kill "$pid"
    rm -f "$pidfile"
}

load_update_args() {
    NUM_PKGS="$3"
    TOTAL_INSTALLED_SIZE_KB="$4"
    [ -n "$TOTAL_INSTALLED_SIZE_KB" ] || TOTAL_INSTALLED_SIZE_KB=0
    # numeric argument means max installed size, otherwise it is flag
    if [[ "$5" =~ ^[0-9]+$ ]]; then
        MAX_INSTALLED_SIZE_KB="$5"
        FLAG="$6"
    else
        MAX_INSTALLED_SIZE_KB=0
        FLAG="$5"
    fi
}

case "$ACTION" in
    init)
	if [ -f /etc/spinetix-release ]; then
	    echo -n "Current firmware version: "
	    cat /etc/spinetix-release
	else
	    echo "Firmware version file not found, firmware version unknown"
	fi
	[ -f "$EXTERNALXML" ] || generate_external_xml
        # make sure moved files state is clean
        rm -rf "$MOVEDFILESDIR"
	;;
    test)
        load_update_args "$@"
	# Only attempt to stop the player if the caller version
	# is the same as our version
        [ "$CALLER_VERSION" = "$VERSION" -a "$FLAG" != "no-stop" ] && stop_player
        # making room has to be done after the player is stopped, otherwise
        # the inodes of the original files may remain in use, preventing the
        # space from being freed
        prepare_for_large_updates "$MAX_INSTALLED_SIZE_KB"
        ;;
    update)
        load_update_args "$@"
	# remove left-over locale and doc files (leave doc on devel systems)
	remove_locale_files
	[ -d /usr/src/debug ] || remove_doc_files
	# need to make /boot rw
	grep -q '^[^[:space:]]\+[[:space:]]\+/boot[[:space:]]' /proc/mounts && \
	    mount -o remount,rw /boot
        # Do not do anything else if updating just a few packages and with small size
        # (safer if updating only the updater)
        if [ -z "$NUM_PKGS" ] || [ "$NUM_PKGS" -lt 10 -a "$TOTAL_INSTALLED_SIZE_KB" -lt 10240 ]; then
	    exit 0
	fi
	# Only attempt to stop the player if the caller version
	# is the same as our version
        [ "$CALLER_VERSION" = "$VERSION" -a "$FLAG" != "no-stop" ] && stop_player
        # making room has to be done after the player is stopped, otherwise
        # the inodes of the original files may remain in use, preventing the
        # space from being freed
        prepare_for_large_updates "$MAX_INSTALLED_SIZE_KB"
	;;
    failtest|failupdate)
        # resture any files that were moved in test / update hook
        [ -e "$MOVEDFILESDIR"/restore ] && "$MOVEDFILESDIR"/restore
        ;;
    posttest)
        # restore any of the files moved to make room for the update, now
        # that all that was to be removed has been removed
        [ -e "$MOVEDFILESDIR"/restore ] && "$MOVEDFILESDIR"/restore
        ;;
    postupdate)
	# signal that boot log is to be preserved on next reboot
	touch /var/lib/updater/keep-bootlog
	if type fsync >/dev/null 2>/dev/null ; then
	    fsync /var/lib/updater/keep-bootlog /var/lib/updater/
	else
	    sync
	fi
	# init changed the pipe location from /dev to /run, create a compat link if
	# the currently running init uses the old path to ensure compatibility with
	# installed init tools potentially using new one
	[ -e /run/initctl -o ! /dev/initctl ] || ln -s /dev/initctl /run/initctl
        # remove generated $EXTERNALXML file just in case we re-run
        rm -f "$EXTERNALXML"
	# remove left-over locale and doc files (leave doc on devel systems)
	remove_locale_files
	[ -d /usr/src/debug ] || remove_doc_files
	# workaround problems when libc does not match nscd version
	workaround_nscd_libc_desync
	# process any package removals
	process_removals
	# remove old kernels
	remove_old_kernels
	restore_kimg_link
        # restore any of the files moved to make room for the update, now
        # that all that was to be removed has been removed
        [ -e "$MOVEDFILESDIR"/restore ] && "$MOVEDFILESDIR"/restore
	# recover any .rpmsave files that could have been left behind (safety net)
	recover_rpmsave
	# repair any missing alternative links that may occur due to file paths that
	# were not under alternatives now being handled by alternatives
	if update-alternatives --help 2>&1 | grep -q -- '[[:space:]]--repair[[:space:]]*$'; then
	    update-alternatives --repair
	else
	    echo "update-alternatives does not support --repair, skipping"
	fi
	# we should remount /boot ro it is was remounted rw, but that
	# will be done anyhow by the reboot that always follows a
	# firmware update
	;;
    download)
	clear_logs
	;;
esac

exit 0
