File: [local] / openbsd / fw_update / fw_install.sh (download)
Revision 1.64, Thu Dec 9 02:37:38 2021 UTC (2 years, 6 months ago) by afresh1
Branch: MAIN
Changes since 1.63: +20 -5 lines
Add support for installing from a local dir
That way we can download the firmware while the network works and install it
when it doesn't.
I envision this being used to make it so firmware can be installed
by syspatch even when the install kernel doesn't have working internet,
maybe a connection that doesn't come up automatically or something.
This would also mean that if the bsd.upgrade kernel fails to boot for some
reason, we boot back into the previous system with the previous firmware that
was already working without having installed a firmware that doesn't work with
this kernel. This would be mostly useful for full version upgrades not snapshots,
but there could be days when it's important.
|
#!/bin/ksh
# $OpenBSD$
#
# Copyright (c) 2021 Andrew Hewus Fresh <afresh1@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
set -o errexit -o pipefail -o nounset
CFILE=SHA256.sig
DESTDIR=${DESTDIR:-}
FWPATTERNS="${DESTDIR}/usr/share/misc/firmware_patterns"
VNAME=${VNAME:-$(sysctl -n kern.osrelease)}
VERSION=${VERSION:-"${VNAME%.*}${VNAME#*.}"}
HTTP_FWDIR="$VNAME"
VTYPE=$( sed -n "/^OpenBSD $VNAME\([^ ]*\).*$/s//\1/p" \
/var/run/dmesg.boot | sed '$!d' )
[[ $VTYPE == -!(stable) ]] && HTTP_FWDIR=snapshots
FWURL=http://firmware.openbsd.org/firmware/${HTTP_FWDIR}
FWPUB_KEY=${DESTDIR}/etc/signify/openbsd-${VERSION}-fw.pub
tmpdir() {
local _i=1 _dir
# If we're not in the installer,
# we have mktemp and a more hostile environment
if [ -x /usr/bin/mktemp ]; then
_dir=$( mktemp -d "${1}-XXXXXXXXX" )
else
until _dir="${1}.$_i.$RANDOM" && mkdir -- "$_dir" 2>/dev/null; do
((++_i < 10000)) || return 1
done
fi
echo "$_dir"
}
realpath () {
if [ -x /usr/bin/realpath ]; then
/usr/bin/realpath "$1"
elif [ "$1" = "${1%/*}" ]; then
echo "${PWD}/$1"
else
echo "$( cd "${1%/*}" && pwd )/${1##*/}"
fi
}
fetch() {
local _file=$1 _user=_file _exit
# If we're not in the installer, we have su(1)
# and doas(1) is unlikely to be configured.
if [ -x /usr/bin/su ]; then
/usr/bin/su -s /bin/ksh "$_user" -c \
"/usr/bin/ftp -D 'Get/Verify' -Vm \
-o- '${FWURL}/${_file}'" > "$_file"
_exit="$?"
else
/usr/bin/doas -u "$_user" \
ftp -D 'Get/Verify' -Vm \
-o- "${FWURL}/${_file}" > "$_file"
_exit="$?"
fi
if [ "$_exit" -ne 0 ]; then
rm -f "$_file"
echo "Cannot fetch $_file" >&2
return 1
fi
}
verify() {
# On the installer we don't get sha256 -C, so fake it.
if ! fgrep -qx "SHA256 ($1) = $( /bin/sha256 -qb "$1" )" "$CFILE"; then
echo "Checksum test for $1 failed." >&2
return 1
fi
}
devices_needing_firmware() {
local _d _m _grep _dmesgtail _last=''
# When we're not in the installer, the dmesg.boot can
# contain multiple boots, so only look in the last one
_dmesgtail=$( sed -n 'H;/^OpenBSD/h;${g;p;}' /var/run/dmesg.boot )
grep -v '^[[:space:]]*#' "$FWPATTERNS" |
while read -r _d _m; do
_grep="grep"
[ "$_last" = "$_d" ] && continue
[ "$_m" ] || _m="^${_d}[0-9][0-9]* at "
[ "$_m" = "${_m#^}" ] && _grep="fgrep"
echo "$_dmesgtail" | $_grep -q "$_m" || continue
echo "$_d"
_last="$_d"
done
}
firmware_filename() {
local _f
_f="$( sed -n "s/.*(\($1-firmware-.*\.tgz\)).*/\1/p" "$CFILE" | sed '$!d' )"
! [ "$_f" ] && echo "Unable to find firmware for $1" >&2 && return 1
echo "$_f"
}
firmware_devicename() {
local _d="${1##*/}"
_d="${_d%-firmware-*}"
echo "$_d"
}
installed_firmware() {
for fw in "${DESTDIR}/var/db/pkg/$1-firmware"*; do
[ -e "$fw" ] || continue
echo "${fw##*/}"
done
}
add_firmware () {
local _f="${1##*/}" _pkgdir="${DESTDIR}/var/db/pkg"
ftp -D "Install" -Vmo- "file:${1}" |
tar -s ",^\+,${_pkgdir}/${_f%.tgz}/+," \
-s ",^firmware,${DESTDIR}/etc/firmware," \
-C / -zxphf - "+*" "firmware/*"
# TODO: Should we mark these so real fw_update can -Drepair?
ed -s "${_pkgdir}/${_f%.tgz}/+CONTENTS" <<EOL
/^@comment pkgpath/ -1a
@option manual-installation
@option firmware
@comment install-script
.
w
EOL
}
delete_firmware() {
local _cwd _pkg="$1" _pkgdir="${DESTDIR}/var/db/pkg"
# TODO: Check hash for files before deleting
echo "Uninstalling $_pkg"
_cwd="${_pkgdir}/$_pkg"
set -A _remove -- "${_cwd}/+CONTENTS" "${_cwd}"
while read -r c g; do
case $c in
@cwd) _cwd="${DESTDIR}$g"
;;
@*) continue
;;
*) set -A _remove -- "$_cwd/$c" "${_remove[@]}"
;;
esac
done < "${_pkgdir}/${_pkg}/+CONTENTS"
# We specifically rm -f here because not removing files/dirs
# is probably not worth failing over.
for _r in "${_remove[@]}" ; do
if [ -d "$_r" ]; then
# Try hard not to actually remove recursively
# without rmdir on the install media.
[ "$_r/*" = "$( echo "$_r"/* )" ] && rm -rf "$_r"
else
rm -f "$_r"
fi
done
}
usage() {
echo "Usage: fw_install [ -d dir | -L dir ] [ driver | file [ ... ] ]"
exit 2
}
DOWNLOADDIR=
LOCALDIR=
while getopts d:L: name
do
case "$name" in
d) DOWNLOADDIR=$OPTARG ;;
L) LOCALDIR=$OPTARG ;;
?) usage 2 ;;
esac
done
shift $((OPTIND - 1))
if [[ -n "${DOWNLOADDIR:-}" && -n "${LOCALDIR:-}" ]]; then
echo "Cannot use -d and -L" >&2
usage 2
fi
set -A devices -- "$@"
[ "${devices[*]:-}" ] ||
set -A devices -- $( devices_needing_firmware )
if [ ! "${devices:-}" ]; then
echo "No devices found which need firmware files to be downloaded."
exit
fi
# Have to find the full path to firmware files
# so we can cd and still find them later.
i=0
while (( i < "${#devices[@]}" )); do
f="${devices[$i]}"
d=$( firmware_devicename "$f" )
[ "$f" = "$d" ] && f="$( echo "$f"-firmware-*.tgz | sed '$!d' )"
if [ -e "$f" ]; then
if [ "${DOWNLOADDIR:-}" ]; then
echo "Cannot download local file $f" >&2
exit 2
fi
devices[$i]="$d:$( realpath "$f" )"
fi
i=$((i + 1))
done
if [ "$DOWNLOADDIR" ]; then
if ! cd "$DOWNLOADDIR"; then
echo "Unable to use $DOWNLOADDIR, make sure it is a directory"
exit 2
fi
elif [ "$LOCALDIR" ]; then
if ! cd "$LOCALDIR"; then
echo "Unable to use $LOCALDIR, make sure it is a directory"
exit 2
fi
else
TMPDIR=$( tmpdir "${DESTDIR}/tmp/fw_install" )
cd "$TMPDIR"
fi
if ! [[ -n "$LOCALDIR" && -e "$CFILE" ]]; then
fetch "$CFILE"
! signify -qVep "$FWPUB_KEY" -x "$CFILE" -m "$CFILE" &&
echo "Signature check of SHA256.sig failed" >&2 && exit 1
fi
for d in "${devices[@]}"; do
f="${d##*:}"
if [ "$f" = "$d" ]; then
f=$( firmware_filename "$d" || true )
[ "$f" ] || continue
else
d="${d%:*}"
fi
set -A installed -- $( installed_firmware "$d" )
if [ ! "${DOWNLOADDIR:-}" ] && [ "${installed:-}" ]; then
for i in "${installed[@]:-}"; do
if [ "${f##*/}" = "$i.tgz" ]; then
echo "$i already installed"
continue 2
fi
done
fi
if [ ! -e "$f" ]; then
[ "$LOCALDIR" ] && echo "Cannot install $f, not found" >&2 && continue
fetch "$f" || continue
verify "$f" || continue
elif [ "${DOWNLOADDIR:-}" ]; then
echo "Already have $f"
verify "$f" || continue
fi
[ "${DOWNLOADDIR:-}" ] && continue
if [ "${installed:-}" ]; then
for i in "${installed[@]}"; do
delete_firmware "$i"
done
fi
add_firmware "$f"
done