Return to fw_install.sh CVS log | Up to [local] / openbsd / fw_update |
File: [local] / openbsd / fw_update / fw_install.sh (download)
Revision 1.8, Sat Oct 16 18:31:13 2021 UTC (2 years, 8 months ago) by afresh1
Be more like the installer Although much stuff left to do to tidy it up, it's getting closer. But, getting closer to being able to shim it in. |
#!/bin/ksh set -e scan_dmesg() { # no bsort for now sed -n "$1" /var/run/dmesg.boot } installed_firmware() { for fw in ${PKGDIR}/$1-firmware*; do [ -e "$fw" ] || continue echo ${fw##*/} done } # tmpdir, do_as, unpriv, and unpriv2 are from install.sub # Create a temporary directory based on the supplied directory name prefix. tmpdir() { local _i=1 _dir until _dir="${1?}.$_i.$RANDOM" && mkdir -- "$_dir" 2>/dev/null; do ((++_i < 10000)) || return 1 done echo "$_dir" } # Run a command ($2+) as unprivileged user ($1). # Take extra care that after "cmd" no "user" processes exist. # # Optionally: # - create "file" and chown it to "user" # - after "cmd", chown "file" back to root # # Usage: do_as user [-f file] cmd do_as() { (( $# >= 2 )) || return local _file _rc _user=$1 shift if [[ $1 == -f ]]; then _file=$2 shift 2 fi if [[ -n $_file ]]; then >$_file chown "$_user" "$_file" fi doas -u "$_user" "$@" _rc=$? while doas -u "$_user" kill -9 -1 2>/dev/null; do echo "Processes still running for user $_user after: $@" sleep 1 done [[ -n $_file ]] && chown root "$_file" return $_rc } unpriv() { do_as _sndio "$@" } unpriv2() { do_as _file "$@" } _issue= fail() { echo $_issue >&2 exit 1 } VNAME=$(sysctl -n kern.osrelease) VERSION="${VNAME%.*}${VNAME#*.}" FWDIR="$VNAME" HTTP_FWDIR=$FWDIR set -- $(scan_dmesg "/^OpenBSD $VNAME\([^ ]*\).*$/s//\1/p") [[ $1 == -!(stable) ]] && HTTP_FWDIR=snapshots FWURL=http://firmware.openbsd.org/firmware/${HTTP_FWDIR} FWPUB_KEY=${DESTDIR}/etc/signify/openbsd-${VERSION}-fw.pub PKGDIR=${DESTDIR}/var/db/pkg PATTERNS="file:${0%/*}/firmware_patterns" drivers=$( last='' ftp -D "Detecting" -Vmo- $PATTERNS | while read d m; do grep=grep [ "$last" = "$d" ] && continue [ "$m" ] || m="^$d[0-9][0-9]* at " [ "$m" = "${m#^}" ] && grep=fgrep $grep -q "$m" /var/run/dmesg.boot || continue echo $d last=$d done ) if [ -z "$drivers" ]; then echo "No devices found which need firmware files to be downloaded." >&2 exit 0 fi _src=$FWURL if _tmpsrc=$( tmpdir "${DESTDIR}/tmp/fw_update" ); then ( >$_tmpsrc/t && $_unpriv cat $_tmpsrc/t ) >/dev/null 2>&1 || rm -r $_tmpsrc fi [[ ! -d $_tmpsrc ]] && _issue="Cannot create prefetch area" && fail cd "$_tmpsrc" _t=Get _cfile="$_tmpsrc/SHA256" _srclocal=false ! $_unpriv ftp -D "$_t" -Vmo - "$_src/SHA256.sig" >"$_cfile.sig" && _issue="Cannot fetch SHA256.sig" && fail # Verify signature file with public keys. ! unpriv -f "$_cfile" \ signify -Vep $FWPUB_KEY -x "$_cfile.sig" -m "$_cfile" && _issue="Signature check of SHA256.sig failed" && fail for d in $drivers; do _f=$( sed -n "s/.*(\($d-firmware-.*\.tgz\)).*/\1/p" "$_cfile" ) installed=$( installed_firmware "$d" ) for i in $installed; do if [ "$_f" = "$i.tgz" ]; then echo "Firmware for $d already installed ($installed)" continue 2 fi done rm -f /tmp/h /tmp/fail _t=Get/Verify # Fetch firmware file and create a checksum by piping through # sha256. Create a flag file in case ftp failed. Firmware # from net is written to the prefetch area. ( $_unpriv ftp -D "$_t" -Vmo - "$_src/$_f" || >/tmp/fail ) | ( $_srclocal && unpriv2 sha256 -b >/tmp/h || unpriv2 -f /tmp/h sha256 -bph /tmp/h >"$_tmpsrc/$_f" ) # Handle failed transfer. if [[ -f /tmp/fail ]]; then rm -f "$_tmpsrc/$_f" _issue="Fetching of $_f failed!" fail fi # Verify firmware by comparing its checksum with SHA256. if fgrep -qx "SHA256 ($_f) = $(</tmp/h)" "$_cfile"; then #_unver=$(rmel $_f $_unver) true else [[ -d "$_tmpsrc" ]] && rm -rf "$_tmpsrc" _issue="Checksum test for $_f failed." fail fi # TODO: Check hash for files before deleting if [ "$installed" ] && [ -e "${PKGDIR}/$installed/+CONTENTS" ]; then echo "Uninstalling $installed" cwd=${PKGDIR}/$installed remove="${cwd}/+CONTENTS ${cwd}" while read c g; do case $c in @cwd) cwd=$g ;; @*) continue ;; *) remove="$cwd/$c $remove" ;; esac done < "${PKGDIR}/$installed/+CONTENTS" 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 fi # TODO: Add some details about the install to +CONTENTS like pkg_add # TODO: Or, maybe we save the firmware someplace and make pkg_add reinstall echo "Installing $_f" tar -zxphf "$_f" -C /etc "firmware/*" mkdir -p ${PKGDIR}/${firmware%.tgz}/ tar -zxphf "$_f" -C "${PKGDIR}/${firmware%.tgz}" "+*" ed -s "${PKGDIR}/${firmware%.tgz}/+CONTENTS" <<EOL /^@comment pkgpath/ -1a @option manual-installation @option firmware @comment install-script . w EOL done