181b30a31Safresh1#!/bin/ksh 2*78b9b1e6Safresh1# $OpenBSD: fw_update.sh,v 1.62 2024/11/24 21:27:04 afresh1 Exp $ 3f07f38fcSafresh1# 4d60efbf6Safresh1# Copyright (c) 2021,2023 Andrew Hewus Fresh <afresh1@openbsd.org> 5f07f38fcSafresh1# 6f07f38fcSafresh1# Permission to use, copy, modify, and distribute this software for any 7f07f38fcSafresh1# purpose with or without fee is hereby granted, provided that the above 8f07f38fcSafresh1# copyright notice and this permission notice appear in all copies. 9f07f38fcSafresh1# 10f07f38fcSafresh1# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11f07f38fcSafresh1# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12f07f38fcSafresh1# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13f07f38fcSafresh1# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14f07f38fcSafresh1# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15f07f38fcSafresh1# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16f07f38fcSafresh1# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17f07f38fcSafresh1 1881b30a31Safresh1set -o errexit -o pipefail -o nounset -o noclobber -o noglob 1981b30a31Safresh1set +o monitor 2081b30a31Safresh1export PATH=/usr/bin:/bin:/usr/sbin:/sbin 21f07f38fcSafresh1 2281b30a31Safresh1CFILE=SHA256.sig 2381b30a31Safresh1DESTDIR=${DESTDIR:-} 2481b30a31Safresh1FWPATTERNS="${DESTDIR}/usr/share/misc/firmware_patterns" 2581b30a31Safresh1 2681b30a31Safresh1VNAME=${VNAME:-$(sysctl -n kern.osrelease)} 2781b30a31Safresh1VERSION=${VERSION:-"${VNAME%.*}${VNAME#*.}"} 2881b30a31Safresh1 2981b30a31Safresh1HTTP_FWDIR="$VNAME" 3081b30a31Safresh1VTYPE=$( sed -n "/^OpenBSD $VNAME\([^ ]*\).*$/s//\1/p" \ 3181b30a31Safresh1 /var/run/dmesg.boot | sed '$!d' ) 320bdd0b6fSafresh1[ "$VTYPE" = -current ] && HTTP_FWDIR=snapshots 3381b30a31Safresh1 3481b30a31Safresh1FWURL=http://firmware.openbsd.org/firmware/${HTTP_FWDIR} 3581b30a31Safresh1FWPUB_KEY=${DESTDIR}/etc/signify/openbsd-${VERSION}-fw.pub 3681b30a31Safresh1 3781b30a31Safresh1DRYRUN=false 38c4d555d4Safresh1integer VERBOSE=0 3981b30a31Safresh1DELETE=false 4081b30a31Safresh1DOWNLOAD=true 4181b30a31Safresh1INSTALL=true 4281b30a31Safresh1LOCALSRC= 43d60efbf6Safresh1ENABLE_SPINNER=false 44d60efbf6Safresh1[ -t 1 ] && ENABLE_SPINNER=true 45d60efbf6Safresh1 46d60efbf6Safresh1integer STATUS_FD=1 47d60efbf6Safresh1integer WARN_FD=2 48d60efbf6Safresh1FD_DIR= 4981b30a31Safresh1 5081b30a31Safresh1unset FTPPID 5153baf8a7Safresh1unset LOCKPID 5281b30a31Safresh1unset FWPKGTMP 5381b30a31Safresh1REMOVE_LOCALSRC=false 548eda69bdSafresh1DROP_PRIVS=true 55d60efbf6Safresh1 56d60efbf6Safresh1status() { echo -n "$*" >&"$STATUS_FD"; } 57d60efbf6Safresh1warn() { echo "$*" >&"$WARN_FD"; } 58d60efbf6Safresh1 5981b30a31Safresh1cleanup() { 6081b30a31Safresh1 set +o errexit # ignore errors from killing ftp 61d60efbf6Safresh1 62d60efbf6Safresh1 if [ -d "$FD_DIR" ]; then 63d60efbf6Safresh1 echo "" >&"$STATUS_FD" 648e9ff1e6Safresh1 ((STATUS_FD == 3)) && exec 3>&- 658e9ff1e6Safresh1 ((WARN_FD == 4)) && exec 4>&- 66d60efbf6Safresh1 67d60efbf6Safresh1 [ -s "$FD_DIR/status" ] && cat "$FD_DIR/status" 68d60efbf6Safresh1 [ -s "$FD_DIR/warn" ] && cat "$FD_DIR/warn" >&2 69d60efbf6Safresh1 70d60efbf6Safresh1 rm -rf "$FD_DIR" 71d60efbf6Safresh1 fi 72d60efbf6Safresh1 7381b30a31Safresh1 [ "${FTPPID:-}" ] && kill -TERM -"$FTPPID" 2>/dev/null 7453baf8a7Safresh1 [ "${LOCKPID:-}" ] && kill -TERM -"$LOCKPID" 2>/dev/null 7581b30a31Safresh1 [ "${FWPKGTMP:-}" ] && rm -rf "$FWPKGTMP" 7681b30a31Safresh1 "$REMOVE_LOCALSRC" && rm -rf "$LOCALSRC" 77d60efbf6Safresh1 [ -e "$CFILE" ] && [ ! -s "$CFILE" ] && rm -f "$CFILE" 78f07f38fcSafresh1} 7981b30a31Safresh1trap cleanup EXIT 8081b30a31Safresh1 8181b30a31Safresh1tmpdir() { 8281b30a31Safresh1 local _i=1 _dir 8381b30a31Safresh1 841d1249f3Safresh1 # The installer lacks mktemp(1), do it by hand 8581b30a31Safresh1 if [ -x /usr/bin/mktemp ]; then 8681b30a31Safresh1 _dir=$( mktemp -d "${1}-XXXXXXXXX" ) 8781b30a31Safresh1 else 8881b30a31Safresh1 until _dir="${1}.$_i.$RANDOM" && mkdir -- "$_dir" 2>/dev/null; do 8981b30a31Safresh1 ((++_i < 10000)) || return 1 9081b30a31Safresh1 done 9181b30a31Safresh1 fi 9281b30a31Safresh1 9381b30a31Safresh1 echo "$_dir" 94f07f38fcSafresh1} 95f07f38fcSafresh1 96d60efbf6Safresh1spin() { 97d60efbf6Safresh1 if ! "$ENABLE_SPINNER"; then 98d60efbf6Safresh1 sleep 1 99d60efbf6Safresh1 return 0 100d60efbf6Safresh1 fi 101d60efbf6Safresh1 102d60efbf6Safresh1 { 103d60efbf6Safresh1 for p in '/' '-' '\\' '|' '/' '-' '\\' '|'; do 1040e3a0897Safresh1 echo -n "$p"'\b' 105d60efbf6Safresh1 sleep 0.125 106d60efbf6Safresh1 done 1070e3a0897Safresh1 echo -n " "'\b' 108d60efbf6Safresh1 }>/dev/tty 109d60efbf6Safresh1} 110d60efbf6Safresh1 11181b30a31Safresh1fetch() { 11281b30a31Safresh1 local _src="${FWURL}/${1##*/}" _dst=$1 _user=_file _exit _error='' 113eaf1d082Safresh1 local _ftp_errors="$FD_DIR/ftp_errors" 114eaf1d082Safresh1 rm -f "$_ftp_errors" 115f07f38fcSafresh1 1161d1249f3Safresh1 # The installer uses a limited doas(1) as a tiny su(1) 11781b30a31Safresh1 set -o monitor # make sure ftp gets its own process group 11881b30a31Safresh1 ( 119c4d555d4Safresh1 _flags=-vm 120c4d555d4Safresh1 case "$VERBOSE" in 121eaf1d082Safresh1 0|1) _flags=-VM ; exec 2>"$_ftp_errors" ;; 122c4d555d4Safresh1 2) _flags=-Vm ;; 123c4d555d4Safresh1 esac 124eaf1d082Safresh1 1258eda69bdSafresh1 if ! "$DROP_PRIVS"; then 1268eda69bdSafresh1 /usr/bin/ftp -N error -D 'Get/Verify' $_flags -o- "$_src" > "$_dst" 1278eda69bdSafresh1 elif [ -x /usr/bin/su ]; then 12881b30a31Safresh1 exec /usr/bin/su -s /bin/ksh "$_user" -c \ 129eaf1d082Safresh1 "/usr/bin/ftp -N error -D 'Get/Verify' $_flags -o- '$_src'" > "$_dst" 13081b30a31Safresh1 else 13181b30a31Safresh1 exec /usr/bin/doas -u "$_user" \ 132eaf1d082Safresh1 /usr/bin/ftp -N error -D 'Get/Verify' $_flags -o- "$_src" > "$_dst" 13381b30a31Safresh1 fi 13481b30a31Safresh1 ) & FTPPID=$! 13581b30a31Safresh1 set +o monitor 136f07f38fcSafresh1 13781b30a31Safresh1 SECONDS=0 13881b30a31Safresh1 _last=0 13981b30a31Safresh1 while kill -0 -"$FTPPID" 2>/dev/null; do 14081b30a31Safresh1 if [[ $SECONDS -gt 12 ]]; then 14181b30a31Safresh1 set -- $( ls -ln "$_dst" 2>/dev/null ) 14281b30a31Safresh1 if [[ $_last -ne $5 ]]; then 14381b30a31Safresh1 _last=$5 14481b30a31Safresh1 SECONDS=0 145d60efbf6Safresh1 spin 14681b30a31Safresh1 else 1478fccd469Safresh1 kill -INT -"$FTPPID" 2>/dev/null 14881b30a31Safresh1 _error=" (timed out)" 14981b30a31Safresh1 fi 15081b30a31Safresh1 else 151d60efbf6Safresh1 spin 15281b30a31Safresh1 fi 15381b30a31Safresh1 done 15481b30a31Safresh1 15581b30a31Safresh1 set +o errexit 15681b30a31Safresh1 wait "$FTPPID" 15781b30a31Safresh1 _exit=$? 15881b30a31Safresh1 set -o errexit 15981b30a31Safresh1 16081b30a31Safresh1 unset FTPPID 16181b30a31Safresh1 162eaf1d082Safresh1 if ((_exit != 0)); then 16381b30a31Safresh1 rm -f "$_dst" 164eaf1d082Safresh1 165eaf1d082Safresh1 # ftp doesn't provide useful exit codes 166eaf1d082Safresh1 # so we have to grep its STDERR. 167eaf1d082Safresh1 # _exit=2 means don't keep trying 168eaf1d082Safresh1 _exit=2 169eaf1d082Safresh1 170eaf1d082Safresh1 # If it was 404, we might succeed at another file 171eaf1d082Safresh1 if [ -s "$_ftp_errors" ] && \ 172eaf1d082Safresh1 grep -q "404 Not Found" "$_ftp_errors"; then 173eaf1d082Safresh1 _exit=1 174eaf1d082Safresh1 _error=" (404 Not Found)" 175eaf1d082Safresh1 rm -f "$_ftp_errors" 17681b30a31Safresh1 fi 177d83d3c9fSafresh1 178eaf1d082Safresh1 warn "Cannot fetch $_src$_error" 179eaf1d082Safresh1 fi 180eaf1d082Safresh1 181eaf1d082Safresh1 # If we have ftp errors, print them out, 182eaf1d082Safresh1 # removing any cntrl characters (like 0x0d), 183eaf1d082Safresh1 # and any leading blank lines. 184eaf1d082Safresh1 if [ -s "$_ftp_errors" ]; then 185eaf1d082Safresh1 sed -e 's/[[:cntrl:]]//g' \ 186eaf1d082Safresh1 -e '/./,$!d' "$_ftp_errors" >&"$WARN_FD" 187eaf1d082Safresh1 fi 188eaf1d082Safresh1 189eaf1d082Safresh1 return "$_exit" 190d83d3c9fSafresh1} 191d83d3c9fSafresh1 1924e4477fdSafresh1# If we fail to fetch the CFILE, we don't want to try again 1934e4477fdSafresh1# but we might be doing this in a subshell so write out 1944e4477fdSafresh1# a blank file indicating failure. 1954e4477fdSafresh1check_cfile() { 1964e4477fdSafresh1 if [ -e "$CFILE" ]; then 197eaf1d082Safresh1 [ -s "$CFILE" ] || return 2 1984e4477fdSafresh1 return 0 1994e4477fdSafresh1 fi 200d60efbf6Safresh1 if ! fetch_cfile; then 2014e4477fdSafresh1 echo -n > "$CFILE" 202eaf1d082Safresh1 return 2 2034e4477fdSafresh1 fi 2044e4477fdSafresh1 return 0 2054e4477fdSafresh1} 2064e4477fdSafresh1 207d83d3c9fSafresh1fetch_cfile() { 208d83d3c9fSafresh1 if "$DOWNLOAD"; then 209d83d3c9fSafresh1 set +o noclobber # we want to get the latest CFILE 210d83d3c9fSafresh1 fetch "$CFILE" || return 1 211d83d3c9fSafresh1 set -o noclobber 2129ba7c5ccSafresh1 signify -qVep "$FWPUB_KEY" -x "$CFILE" -m /dev/null \ 2139ba7c5ccSafresh1 2>&"$WARN_FD" || { 2149ba7c5ccSafresh1 warn "Signature check of SHA256.sig failed" 2159ba7c5ccSafresh1 rm -f "$CFILE" 2169ba7c5ccSafresh1 return 1 2179ba7c5ccSafresh1 } 218d83d3c9fSafresh1 elif [ ! -e "$CFILE" ]; then 219d60efbf6Safresh1 warn "${0##*/}: $CFILE: No such file or directory" 2204e4477fdSafresh1 return 1 221d83d3c9fSafresh1 fi 222d83d3c9fSafresh1 223d83d3c9fSafresh1 return 0 224f07f38fcSafresh1} 225f07f38fcSafresh1 22681b30a31Safresh1verify() { 227eaf1d082Safresh1 check_cfile || return $? 2281d1249f3Safresh1 # The installer sha256 lacks -C, do it by hand 229d60efbf6Safresh1 if ! grep -Fqx "SHA256 (${1##*/}) = $( /bin/sha256 -qb "$1" )" "$CFILE" 230d60efbf6Safresh1 then 231d60efbf6Safresh1 ((VERBOSE != 1)) && warn "Checksum test for ${1##*/} failed." 23281b30a31Safresh1 return 1 23381b30a31Safresh1 fi 234d83d3c9fSafresh1 235d83d3c9fSafresh1 return 0 23681b30a31Safresh1} 23781b30a31Safresh1 238d60efbf6Safresh1# When verifying existing files that we are going to re-download 239d60efbf6Safresh1# if VERBOSE is 0, don't show the checksum failure of an existing file. 240d60efbf6Safresh1verify_existing() { 241d60efbf6Safresh1 local _v=$VERBOSE 242eaf1d082Safresh1 check_cfile || return $? 243d60efbf6Safresh1 244d60efbf6Safresh1 ((_v == 0)) && "$DOWNLOAD" && _v=1 245d60efbf6Safresh1 ( VERBOSE=$_v verify "$@" ) 246d60efbf6Safresh1} 247d60efbf6Safresh1 248*78b9b1e6Safresh1devices_in_dmesg() { 2491c702c4aSafresh1 local IFS 2501c702c4aSafresh1 local _d _m _dmesgtail _last='' _nl=' 2511c702c4aSafresh1' 25281b30a31Safresh1 2531d1249f3Safresh1 # The dmesg can contain multiple boots, only look in the last one 25481b30a31Safresh1 _dmesgtail="$( echo ; sed -n 'H;/^OpenBSD/h;${g;p;}' /var/run/dmesg.boot )" 25581b30a31Safresh1 25681b30a31Safresh1 grep -v '^[[:space:]]*#' "$FWPATTERNS" | 25781b30a31Safresh1 while read -r _d _m; do 25881b30a31Safresh1 [ "$_d" = "$_last" ] && continue 25981b30a31Safresh1 [ "$_m" ] || _m="${_nl}${_d}[0-9] at " 26081b30a31Safresh1 [ "$_m" = "${_m#^}" ] || _m="${_nl}${_m#^}" 26181b30a31Safresh1 2621c702c4aSafresh1 IFS='*' 2631c702c4aSafresh1 set -- $_m 2641c702c4aSafresh1 unset IFS 2651c702c4aSafresh1 2661c702c4aSafresh1 case $# in 2671c702c4aSafresh1 1|2|3) [[ $_dmesgtail = *$1*([!$_nl])${2-}*([!$_nl])${3-}* ]] || continue;; 268d60efbf6Safresh1 *) warn "${0##*/}: Bad pattern '${_m#$_nl}' in $FWPATTERNS"; exit 1 ;; 2691c702c4aSafresh1 esac 2701c702c4aSafresh1 27181b30a31Safresh1 echo "$_d" 27281b30a31Safresh1 _last="$_d" 27381b30a31Safresh1 done 27481b30a31Safresh1} 27581b30a31Safresh1 27681b30a31Safresh1firmware_filename() { 277eaf1d082Safresh1 check_cfile || return $? 2781e63d4eeSafresh1 sed -n "s/.*(\($1-firmware-.*\.tgz\)).*/\1/p" "$CFILE" | sed '$!d' 27981b30a31Safresh1} 28081b30a31Safresh1 28181b30a31Safresh1firmware_devicename() { 28281b30a31Safresh1 local _d="${1##*/}" 28381b30a31Safresh1 _d="${_d%-firmware-*}" 28481b30a31Safresh1 echo "$_d" 28581b30a31Safresh1} 28681b30a31Safresh1 28753baf8a7Safresh1lock_db() { 28897f1001cSafresh1 local _waited 28953baf8a7Safresh1 [ "${LOCKPID:-}" ] && return 0 29053baf8a7Safresh1 29153baf8a7Safresh1 # The installer doesn't have perl, so we can't lock there 29253baf8a7Safresh1 [ -e /usr/bin/perl ] || return 0 29353baf8a7Safresh1 29453baf8a7Safresh1 set -o monitor 29564882388Safresh1 perl <<-'EOL' |& 29632367434Safresh1 no lib ('/usr/local/libdata/perl5/site_perl'); 29764882388Safresh1 use v5.36; 298ef057aebSespie use OpenBSD::PackageInfo qw< lock_db >; 29953baf8a7Safresh1 30053baf8a7Safresh1 $|=1; 30153baf8a7Safresh1 30264882388Safresh1 $0 = "fw_update: lock_db"; 30397f1001cSafresh1 my $waited = 0; 30497f1001cSafresh1 package OpenBSD::FwUpdateState { 30597f1001cSafresh1 use parent 'OpenBSD::BaseState'; 30697f1001cSafresh1 sub errprint ($self, @p) { 30797f1001cSafresh1 if ($p[0] && $p[0] =~ /already locked/) { 30897f1001cSafresh1 $waited++; 30997f1001cSafresh1 $p[0] = " " . $p[0] 31097f1001cSafresh1 if !$ENV{VERBOSE}; 31197f1001cSafresh1 } 31297f1001cSafresh1 $self->SUPER::errprint(@p); 31397f1001cSafresh1 } 31453baf8a7Safresh1 31597f1001cSafresh1 } 31697f1001cSafresh1 lock_db(0, 'OpenBSD::FwUpdateState'); 31797f1001cSafresh1 31897f1001cSafresh1 say "$$ $waited"; 31964882388Safresh1 32064882388Safresh1 # Wait for STDOUT to be readable, which won't happen 32164882388Safresh1 # but if our parent exits unexpectedly it will close. 32264882388Safresh1 my $rin = ''; 32364882388Safresh1 vec($rin, fileno(STDOUT), 1) = 1; 32464882388Safresh1 select $rin, '', '', undef; 32553baf8a7Safresh1EOL 32653baf8a7Safresh1 set +o monitor 32753baf8a7Safresh1 32897f1001cSafresh1 read -rp LOCKPID _waited 32997f1001cSafresh1 33097f1001cSafresh1 if ((_waited)); then 33197f1001cSafresh1 ! ((VERBOSE)) && status "${0##*/}:" 33297f1001cSafresh1 fi 33353baf8a7Safresh1 33453baf8a7Safresh1 return 0 33553baf8a7Safresh1} 33653baf8a7Safresh1 337fe7b3534Safresh1available_firmware() { 338fe7b3534Safresh1 check_cfile || return $? 339fe7b3534Safresh1 sed -n 's/.*(\(.*\)-firmware.*/\1/p' "$CFILE" 340fe7b3534Safresh1} 341fe7b3534Safresh1 34281b30a31Safresh1installed_firmware() { 34357365b05Safresh1 local _pre="$1" _match="$2" _post="$3" _firmware _fw 34481b30a31Safresh1 set -sA _firmware -- $( 34581b30a31Safresh1 set +o noglob 34681b30a31Safresh1 grep -Fxl '@option firmware' \ 34781b30a31Safresh1 "${DESTDIR}/var/db/pkg/"$_pre"$_match"$_post"/+CONTENTS" \ 34881b30a31Safresh1 2>/dev/null || true 34981b30a31Safresh1 set -o noglob 35081b30a31Safresh1 ) 35181b30a31Safresh1 35281b30a31Safresh1 [ "${_firmware[*]:-}" ] || return 0 35357365b05Safresh1 for _fw in "${_firmware[@]}"; do 35457365b05Safresh1 _fw="${_fw%/+CONTENTS}" 35557365b05Safresh1 echo "${_fw##*/}" 35681b30a31Safresh1 done 35781b30a31Safresh1} 35881b30a31Safresh1 35981b30a31Safresh1detect_firmware() { 36081b30a31Safresh1 local _devices _last='' _d 36181b30a31Safresh1 36281b30a31Safresh1 set -sA _devices -- $( 363*78b9b1e6Safresh1 devices_in_dmesg 36481b30a31Safresh1 for _d in $( installed_firmware '*' '-firmware-' '*' ); do 3658fccd469Safresh1 firmware_devicename "$_d" 36681b30a31Safresh1 done 36781b30a31Safresh1 ) 36881b30a31Safresh1 36981b30a31Safresh1 [ "${_devices[*]:-}" ] || return 0 37081b30a31Safresh1 for _d in "${_devices[@]}"; do 3718fccd469Safresh1 [ "$_last" = "$_d" ] && continue 3728fccd469Safresh1 echo "$_d" 37381b30a31Safresh1 _last="$_d" 37481b30a31Safresh1 done 37581b30a31Safresh1} 37681b30a31Safresh1 37781b30a31Safresh1add_firmware () { 3783d362716Safresh1 local _f="${1##*/}" _m="${2:-Install}" 3793d362716Safresh1 local _pkgdir="${DESTDIR}/var/db/pkg" _pkg 38081b30a31Safresh1 FWPKGTMP="$( tmpdir "${DESTDIR}/var/db/pkg/.firmware" )" 381c4d555d4Safresh1 local _flags=-vm 382c4d555d4Safresh1 case "$VERBOSE" in 383c4d555d4Safresh1 0|1) _flags=-VM ;; 384c4d555d4Safresh1 2|3) _flags=-Vm ;; 385c4d555d4Safresh1 esac 386c4d555d4Safresh1 387c4d555d4Safresh1 ftp -N "${0##/}" -D "$_m" "$_flags" -o- "file:${1}" | 38881b30a31Safresh1 tar -s ",^\+,${FWPKGTMP}/+," \ 38981b30a31Safresh1 -s ",^firmware,${DESTDIR}/etc/firmware," \ 39081b30a31Safresh1 -C / -zxphf - "+*" "firmware/*" 39181b30a31Safresh1 3928e9ff1e6Safresh1 3938e9ff1e6Safresh1 [ -s "${FWPKGTMP}/+CONTENTS" ] && 3943d362716Safresh1 _pkg="$( sed -n '/^@name /{s///p;q;}' "${FWPKGTMP}/+CONTENTS" )" 3958e9ff1e6Safresh1 3968e9ff1e6Safresh1 if [ ! "${_pkg:-}" ]; then 3973d362716Safresh1 warn "Failed to extract name from $1, partial install" 3983d362716Safresh1 rm -rf "$FWPKGTMP" 3993d362716Safresh1 unset FWPKGTMP 4003d362716Safresh1 return 1 4013d362716Safresh1 fi 4023d362716Safresh1 4033d362716Safresh1 if [ -e "$_pkgdir/$_pkg" ]; then 4043d362716Safresh1 warn "Failed to register: $_pkgdir/$_pkg is not firmware" 40581b30a31Safresh1 rm -rf "$FWPKGTMP" 40681b30a31Safresh1 unset FWPKGTMP 40781b30a31Safresh1 return 1 40881b30a31Safresh1 fi 40981b30a31Safresh1 41081b30a31Safresh1 ed -s "${FWPKGTMP}/+CONTENTS" <<EOL 41181b30a31Safresh1/^@comment pkgpath/ -1a 41281b30a31Safresh1@option manual-installation 41381b30a31Safresh1@option firmware 41481b30a31Safresh1@comment install-script 41581b30a31Safresh1. 41681b30a31Safresh1w 41781b30a31Safresh1EOL 41881b30a31Safresh1 41981b30a31Safresh1 chmod 755 "$FWPKGTMP" 4203d362716Safresh1 mv "$FWPKGTMP" "$_pkgdir/$_pkg" 42181b30a31Safresh1 unset FWPKGTMP 42281b30a31Safresh1} 42381b30a31Safresh1 4241e63d4eeSafresh1remove_files() { 42557365b05Safresh1 local _r 4261e63d4eeSafresh1 # Use rm -f, not removing files/dirs is probably not worth failing over 4271e63d4eeSafresh1 for _r in "$@" ; do 4281e63d4eeSafresh1 if [ -d "$_r" ]; then 4291e63d4eeSafresh1 # The installer lacks rmdir, 4301e63d4eeSafresh1 # but we only want to remove empty directories. 4311e63d4eeSafresh1 set +o noglob 4321e63d4eeSafresh1 [ "$_r/*" = "$( echo "$_r"/* )" ] && rm -rf "$_r" 4331e63d4eeSafresh1 set -o noglob 4341e63d4eeSafresh1 else 4351e63d4eeSafresh1 rm -f "$_r" 4361e63d4eeSafresh1 fi 4371e63d4eeSafresh1 done 4381e63d4eeSafresh1} 4391e63d4eeSafresh1 44081b30a31Safresh1delete_firmware() { 44181b30a31Safresh1 local _cwd _pkg="$1" _pkgdir="${DESTDIR}/var/db/pkg" 44281b30a31Safresh1 44381b30a31Safresh1 # TODO: Check hash for files before deleting 444c4d555d4Safresh1 ((VERBOSE > 2)) && echo -n "Uninstall $_pkg ..." 44581b30a31Safresh1 _cwd="${_pkgdir}/$_pkg" 44681b30a31Safresh1 44781b30a31Safresh1 if [ ! -e "$_cwd/+CONTENTS" ] || 44881b30a31Safresh1 ! grep -Fxq '@option firmware' "$_cwd/+CONTENTS"; then 449d60efbf6Safresh1 warn "${0##*/}: $_pkg does not appear to be firmware" 45081b30a31Safresh1 return 2 45181b30a31Safresh1 fi 45281b30a31Safresh1 45381b30a31Safresh1 set -A _remove -- "${_cwd}/+CONTENTS" "${_cwd}" 45481b30a31Safresh1 45557365b05Safresh1 while read -r _c _g; do 45657365b05Safresh1 case $_c in 45757365b05Safresh1 @cwd) _cwd="${DESTDIR}$_g" 45881b30a31Safresh1 ;; 45981b30a31Safresh1 @*) continue 46081b30a31Safresh1 ;; 46157365b05Safresh1 *) set -A _remove -- "$_cwd/$_c" "${_remove[@]}" 46281b30a31Safresh1 ;; 46381b30a31Safresh1 esac 46481b30a31Safresh1 done < "${_pkgdir}/${_pkg}/+CONTENTS" 46581b30a31Safresh1 4661e63d4eeSafresh1 remove_files "${_remove[@]}" 467c4d555d4Safresh1 468c4d555d4Safresh1 ((VERBOSE > 2)) && echo " done." 469c4d555d4Safresh1 470c4d555d4Safresh1 return 0 47181b30a31Safresh1} 47281b30a31Safresh1 4731e63d4eeSafresh1unregister_firmware() { 47457365b05Safresh1 local _d="$1" _pkgdir="${DESTDIR}/var/db/pkg" _fw 4751e63d4eeSafresh1 4761e63d4eeSafresh1 set -A installed -- $( installed_firmware '' "$d-firmware-" '*' ) 4771e63d4eeSafresh1 if [ "${installed:-}" ]; then 47857365b05Safresh1 for _fw in "${installed[@]}"; do 47957365b05Safresh1 ((VERBOSE)) && echo "Unregister $_fw" 4801e63d4eeSafresh1 "$DRYRUN" && continue 4811e63d4eeSafresh1 remove_files \ 48257365b05Safresh1 "$_pkgdir/$_fw/+CONTENTS" \ 48357365b05Safresh1 "$_pkgdir/$_fw/+DESC" \ 48457365b05Safresh1 "$_pkgdir/$_fw/" 4851e63d4eeSafresh1 done 4861e63d4eeSafresh1 return 0 4871e63d4eeSafresh1 fi 4881e63d4eeSafresh1 4891e63d4eeSafresh1 return 1 4901e63d4eeSafresh1} 4911e63d4eeSafresh1 49281b30a31Safresh1usage() { 49314dcac1eSafresh1 echo "usage: ${0##*/} [-adFlnv] [-p path] [driver | file ...]" 4948b422bc7Safresh1 exit 1 49581b30a31Safresh1} 49681b30a31Safresh1 49781b30a31Safresh1ALL=false 49814dcac1eSafresh1LIST=false 49914dcac1eSafresh1while getopts :adFlnp:v name 50081b30a31Safresh1do 50181b30a31Safresh1 case "$name" in 50281b30a31Safresh1 a) ALL=true ;; 50381b30a31Safresh1 d) DELETE=true ;; 5043df64845Safresh1 F) INSTALL=false ;; 50514dcac1eSafresh1 l) LIST=true ;; 50681b30a31Safresh1 n) DRYRUN=true ;; 507fcfe10d6Safresh1 p) FWURL="$OPTARG" ;; 508c4d555d4Safresh1 v) ((++VERBOSE)) ;; 50981b30a31Safresh1 :) 510d60efbf6Safresh1 warn "${0##*/}: option requires an argument -- -$OPTARG" 5118b422bc7Safresh1 usage 51281b30a31Safresh1 ;; 51381b30a31Safresh1 ?) 514d60efbf6Safresh1 warn "${0##*/}: unknown option -- -$OPTARG" 5158b422bc7Safresh1 usage 51681b30a31Safresh1 ;; 51781b30a31Safresh1 esac 51881b30a31Safresh1done 51981b30a31Safresh1shift $((OPTIND - 1)) 52081b30a31Safresh1 52114dcac1eSafresh1# When listing, provide a clean output 52214dcac1eSafresh1"$LIST" && VERBOSE=1 ENABLE_SPINNER=false 52314dcac1eSafresh1 524d60efbf6Safresh1# Progress bars, not spinner When VERBOSE > 1 525d60efbf6Safresh1((VERBOSE > 1)) && ENABLE_SPINNER=false 526d60efbf6Safresh1 527fcfe10d6Safresh1if [[ $FWURL != @(ftp|http?(s))://* ]]; then 528fcfe10d6Safresh1 FWURL="${FWURL#file:}" 529fcfe10d6Safresh1 ! [ -d "$FWURL" ] && 530d60efbf6Safresh1 warn "The path must be a URL or an existing directory" && 5318b422bc7Safresh1 exit 1 5323df64845Safresh1 DOWNLOAD=false 533fcfe10d6Safresh1 FWURL="file:$FWURL" 53481b30a31Safresh1fi 53581b30a31Safresh1 53681b30a31Safresh1if [ -x /usr/bin/id ] && [ "$(/usr/bin/id -u)" != 0 ]; then 5373df64845Safresh1 if ! "$INSTALL" || "$LIST"; then 5388eda69bdSafresh1 # When we aren't in the installer, 5398eda69bdSafresh1 # allow downloading as the current user. 5408eda69bdSafresh1 DROP_PRIVS=false 5418eda69bdSafresh1 else 542d60efbf6Safresh1 warn "need root privileges" 54381b30a31Safresh1 exit 1 54481b30a31Safresh1 fi 5458eda69bdSafresh1fi 54681b30a31Safresh1 54781b30a31Safresh1set -sA devices -- "$@" 54881b30a31Safresh1 549d60efbf6Safresh1FD_DIR="$( tmpdir "${DESTDIR}/tmp/${0##*/}-fd" )" 5508e9ff1e6Safresh1# When being verbose, save the status line for the end. 551d60efbf6Safresh1if ((VERBOSE)); then 5528e9ff1e6Safresh1 exec 3>"${FD_DIR}/status" 5538e9ff1e6Safresh1 STATUS_FD=3 5548e9ff1e6Safresh1fi 5558e9ff1e6Safresh1# Control "warning" messages to avoid the middle of a line. 5568e9ff1e6Safresh1# Things that we don't expect to send to STDERR 5578e9ff1e6Safresh1# still go there so the output, while it may be ugly, isn't lost 558d60efbf6Safresh1exec 4>"${FD_DIR}/warn" 559d60efbf6Safresh1WARN_FD=4 560d60efbf6Safresh1 561d60efbf6Safresh1status "${0##*/}:" 562d60efbf6Safresh1 56381b30a31Safresh1if "$DELETE"; then 5643df64845Safresh1 ! "$INSTALL" && warn "Cannot use -F and -d" && usage 56553baf8a7Safresh1 lock_db 56681b30a31Safresh1 567c4d555d4Safresh1 # Show the "Uninstall" message when just deleting not upgrading 568c4d555d4Safresh1 ((VERBOSE)) && VERBOSE=3 569c4d555d4Safresh1 57081b30a31Safresh1 set -A installed 57181b30a31Safresh1 if [ "${devices[*]:-}" ]; then 572d60efbf6Safresh1 "$ALL" && warn "Cannot use -a and devices/files" && usage 57381b30a31Safresh1 57481b30a31Safresh1 set -A installed -- $( 57581b30a31Safresh1 for d in "${devices[@]}"; do 57681b30a31Safresh1 f="${d##*/}" # only care about the name 57781b30a31Safresh1 f="${f%.tgz}" # allow specifying the package name 57881b30a31Safresh1 [ "$( firmware_devicename "$f" )" = "$f" ] && f="$f-firmware" 57981b30a31Safresh1 58081b30a31Safresh1 set -A i -- $( installed_firmware '' "$f-" '*' ) 58181b30a31Safresh1 58281b30a31Safresh1 if [ "${i[*]:-}" ]; then 58381b30a31Safresh1 echo "${i[@]}" 58481b30a31Safresh1 else 585d60efbf6Safresh1 warn "No firmware found for '$d'" 58681b30a31Safresh1 fi 58781b30a31Safresh1 done 58881b30a31Safresh1 ) 58981b30a31Safresh1 elif "$ALL"; then 59081b30a31Safresh1 set -A installed -- $( installed_firmware '*' '-firmware-' '*' ) 591*78b9b1e6Safresh1 else 592*78b9b1e6Safresh1 set -A installed -- $( 593*78b9b1e6Safresh1 set -- $( devices_in_dmesg ) 594*78b9b1e6Safresh1 for f in $( installed_firmware '*' -firmware- '*' ); do 595*78b9b1e6Safresh1 n="$( firmware_devicename "$f" )" 596*78b9b1e6Safresh1 for d; do 597*78b9b1e6Safresh1 [ "$d" = "$n" ] && continue 2 598*78b9b1e6Safresh1 done 599*78b9b1e6Safresh1 echo "$f" 600*78b9b1e6Safresh1 done 601*78b9b1e6Safresh1 ) 60281b30a31Safresh1 fi 60381b30a31Safresh1 604d60efbf6Safresh1 status " delete " 605d60efbf6Safresh1 606d60efbf6Safresh1 comma='' 60781b30a31Safresh1 if [ "${installed:-}" ]; then 60881b30a31Safresh1 for fw in "${installed[@]}"; do 609d60efbf6Safresh1 status "$comma$( firmware_devicename "$fw" )" 610d60efbf6Safresh1 comma=, 61181b30a31Safresh1 if "$DRYRUN"; then 612c4d555d4Safresh1 ((VERBOSE)) && echo "Delete $fw" 61314dcac1eSafresh1 elif "$LIST"; then 61414dcac1eSafresh1 echo "$fw" 61581b30a31Safresh1 else 6168e9ff1e6Safresh1 delete_firmware "$fw" || { 6178e9ff1e6Safresh1 status " ($fw failed)" 6188e9ff1e6Safresh1 continue 6198e9ff1e6Safresh1 } 62081b30a31Safresh1 fi 62181b30a31Safresh1 done 62281b30a31Safresh1 fi 62381b30a31Safresh1 624d60efbf6Safresh1 [ "$comma" ] || status none 62581b30a31Safresh1 62614dcac1eSafresh1 # no status when listing 62714dcac1eSafresh1 "$LIST" && rm -f "$FD_DIR/status" 62814dcac1eSafresh1 62981b30a31Safresh1 exit 63081b30a31Safresh1fi 63181b30a31Safresh1 6323df64845Safresh1! "$INSTALL" && ! "$LIST" && LOCALSRC="${LOCALSRC:-.}" 6333df64845Safresh1 63481b30a31Safresh1if [ ! "$LOCALSRC" ]; then 63581b30a31Safresh1 LOCALSRC="$( tmpdir "${DESTDIR}/tmp/${0##*/}" )" 63681b30a31Safresh1 REMOVE_LOCALSRC=true 63781b30a31Safresh1fi 63881b30a31Safresh1 63981b30a31Safresh1CFILE="$LOCALSRC/$CFILE" 64081b30a31Safresh1 64181b30a31Safresh1if [ "${devices[*]:-}" ]; then 642d60efbf6Safresh1 "$ALL" && warn "Cannot use -a and devices/files" && usage 643fe7b3534Safresh1elif "$ALL"; then 644fe7b3534Safresh1 set -sA devices -- $( available_firmware ) 64581b30a31Safresh1else 646c4d555d4Safresh1 ((VERBOSE > 1)) && echo -n "Detect firmware ..." 64781b30a31Safresh1 set -sA devices -- $( detect_firmware ) 648c4d555d4Safresh1 ((VERBOSE > 1)) && 64981b30a31Safresh1 { [ "${devices[*]:-}" ] && echo " found." || echo " done." ; } 65081b30a31Safresh1fi 65181b30a31Safresh1 65253baf8a7Safresh1 653d60efbf6Safresh1set -A add '' 654d60efbf6Safresh1set -A update '' 65581b30a31Safresh1kept='' 6561e63d4eeSafresh1unregister='' 657d60efbf6Safresh1 6583df64845Safresh1"$LIST" && ! "$INSTALL" && 65914dcac1eSafresh1 echo "$FWURL/${CFILE##*/}" 66014dcac1eSafresh1 6610553a602Safresh1if [ "${devices[*]:-}" ]; then 6620553a602Safresh1 lock_db 66381b30a31Safresh1 for f in "${devices[@]}"; do 66481b30a31Safresh1 d="$( firmware_devicename "$f" )" 66581b30a31Safresh1 6663df64845Safresh1 if "$LIST" && "$INSTALL"; then 66714dcac1eSafresh1 echo "$d" 66814dcac1eSafresh1 continue 66914dcac1eSafresh1 fi 67014dcac1eSafresh1 6717f22cd74Safresh1 verify_existing=true 67281b30a31Safresh1 if [ "$f" = "$d" ]; then 673eaf1d082Safresh1 f=$( firmware_filename "$d" ) || { 674eaf1d082Safresh1 # Fetching the CFILE here is often the 675eaf1d082Safresh1 # first attempt to talk to FWURL 676eaf1d082Safresh1 # If it fails, no point in continuing. 677eaf1d082Safresh1 if (($? > 1)); then 678eaf1d082Safresh1 status " failed." 679eaf1d082Safresh1 exit 1 680eaf1d082Safresh1 fi 681eaf1d082Safresh1 682eaf1d082Safresh1 # otherwise we can try the next firmware 683eaf1d082Safresh1 continue 684eaf1d082Safresh1 } 6851e63d4eeSafresh1 if [ ! "$f" ]; then 6861e63d4eeSafresh1 if "$INSTALL" && unregister_firmware "$d"; then 6871e63d4eeSafresh1 unregister="$unregister,$d" 6881e63d4eeSafresh1 else 689d60efbf6Safresh1 warn "Unable to find firmware for $d" 6901e63d4eeSafresh1 fi 6911e63d4eeSafresh1 continue 6921e63d4eeSafresh1 fi 69381b30a31Safresh1 elif ! "$INSTALL" && ! grep -Fq "($f)" "$CFILE" ; then 694d60efbf6Safresh1 warn "Cannot download local file $f" 6958b422bc7Safresh1 exit 1 696d83d3c9fSafresh1 else 6971d1249f3Safresh1 # Don't verify files specified on the command-line 698d83d3c9fSafresh1 verify_existing=false 69981b30a31Safresh1 fi 70081b30a31Safresh1 70114dcac1eSafresh1 if "$LIST"; then 70214dcac1eSafresh1 echo "$FWURL/$f" 70314dcac1eSafresh1 continue 70414dcac1eSafresh1 fi 70514dcac1eSafresh1 706d60efbf6Safresh1 set -A installed 707d60efbf6Safresh1 if "$INSTALL"; then 708d60efbf6Safresh1 set -A installed -- \ 709d60efbf6Safresh1 $( installed_firmware '' "$d-firmware-" '*' ) 71081b30a31Safresh1 711d60efbf6Safresh1 if [ "${installed[*]:-}" ]; then 71281b30a31Safresh1 for i in "${installed[@]}"; do 71381b30a31Safresh1 if [ "${f##*/}" = "$i.tgz" ]; then 714d60efbf6Safresh1 ((VERBOSE > 2)) \ 715d60efbf6Safresh1 && echo "Keep $i" 71681b30a31Safresh1 kept="$kept,$d" 71781b30a31Safresh1 continue 2 71881b30a31Safresh1 fi 71981b30a31Safresh1 done 72081b30a31Safresh1 fi 721d60efbf6Safresh1 fi 72281b30a31Safresh1 7238ffd1deaSafresh1 # Fetch an unqualified file into LOCALSRC 7248ffd1deaSafresh1 # if it doesn't exist in the current directory. 7258ffd1deaSafresh1 if [ "$f" = "${f##/}" ] && [ ! -e "$f" ]; then 7268ffd1deaSafresh1 f="$LOCALSRC/$f" 7278ffd1deaSafresh1 fi 7288ffd1deaSafresh1 7297f22cd74Safresh1 if "$verify_existing" && [ -e "$f" ]; then 730d60efbf6Safresh1 pending_status=false 731c4d555d4Safresh1 if ((VERBOSE == 1)); then 732c4d555d4Safresh1 echo -n "Verify ${f##*/} ..." 733c4d555d4Safresh1 pending_status=true 7347f22cd74Safresh1 elif ((VERBOSE > 1)) && ! "$INSTALL"; then 73581b30a31Safresh1 echo "Keep/Verify ${f##*/}" 7367f22cd74Safresh1 fi 7377f22cd74Safresh1 738d60efbf6Safresh1 if "$DRYRUN" || verify_existing "$f"; then 739d60efbf6Safresh1 "$pending_status" && echo " done." 740d60efbf6Safresh1 if ! "$INSTALL"; then 741d60efbf6Safresh1 kept="$kept,$d" 742d60efbf6Safresh1 continue 743d60efbf6Safresh1 fi 7447f22cd74Safresh1 elif "$DOWNLOAD"; then 745d60efbf6Safresh1 "$pending_status" && echo " failed." 7467f22cd74Safresh1 ((VERBOSE > 1)) && echo "Refetching $f" 7474e4477fdSafresh1 rm -f "$f" 7487f22cd74Safresh1 else 749c4d555d4Safresh1 "$pending_status" && echo " failed." 750c4d555d4Safresh1 continue 751d83d3c9fSafresh1 fi 7527f22cd74Safresh1 fi 7537f22cd74Safresh1 754d60efbf6Safresh1 if [ "${installed[*]:-}" ]; then 755d60efbf6Safresh1 set -A update -- "${update[@]}" "$f" 756d60efbf6Safresh1 else 757d60efbf6Safresh1 set -A add -- "${add[@]}" "$f" 758d60efbf6Safresh1 fi 759d60efbf6Safresh1 760d60efbf6Safresh1 done 761d60efbf6Safresh1fi 762d60efbf6Safresh1 76314dcac1eSafresh1if "$LIST"; then 76414dcac1eSafresh1 # No status when listing 76514dcac1eSafresh1 rm -f "$FD_DIR/status" 76614dcac1eSafresh1 exit 76714dcac1eSafresh1fi 76814dcac1eSafresh1 769d60efbf6Safresh1if "$INSTALL"; then 770d60efbf6Safresh1 status " add " 771d60efbf6Safresh1 action=Install 772d60efbf6Safresh1else 773d60efbf6Safresh1 status " download " 774d60efbf6Safresh1 action=Download 775d60efbf6Safresh1fi 776d60efbf6Safresh1 777d60efbf6Safresh1comma='' 778d60efbf6Safresh1[ "${add[*]}" ] || status none 779d60efbf6Safresh1for f in "${add[@]}" _update_ "${update[@]}"; do 780d60efbf6Safresh1 [ "$f" ] || continue 781d60efbf6Safresh1 if [ "$f" = _update_ ]; then 782d60efbf6Safresh1 comma='' 783d60efbf6Safresh1 "$INSTALL" || continue 784d60efbf6Safresh1 action=Update 785d60efbf6Safresh1 status "; update " 786d60efbf6Safresh1 [ "${update[*]}" ] || status none 787d60efbf6Safresh1 continue 788d60efbf6Safresh1 fi 789d60efbf6Safresh1 d="$( firmware_devicename "$f" )" 790d60efbf6Safresh1 status "$comma$d" 791d60efbf6Safresh1 comma=, 792d60efbf6Safresh1 793d60efbf6Safresh1 pending_status=false 7947f22cd74Safresh1 if [ -e "$f" ]; then 795d60efbf6Safresh1 if "$DRYRUN"; then 796d60efbf6Safresh1 ((VERBOSE)) && echo "$action ${f##*/}" 797d60efbf6Safresh1 else 798d60efbf6Safresh1 if ((VERBOSE == 1)); then 799d60efbf6Safresh1 echo -n "Install ${f##*/} ..." 800d60efbf6Safresh1 pending_status=true 801d60efbf6Safresh1 fi 802d60efbf6Safresh1 fi 80381b30a31Safresh1 elif "$DOWNLOAD"; then 80481b30a31Safresh1 if "$DRYRUN"; then 805c4d555d4Safresh1 ((VERBOSE)) && echo "Get/Verify ${f##*/}" 80681b30a31Safresh1 else 807c4d555d4Safresh1 if ((VERBOSE == 1)); then 808c4d555d4Safresh1 echo -n "Get/Verify ${f##*/} ..." 809c4d555d4Safresh1 pending_status=true 810c4d555d4Safresh1 fi 811c4d555d4Safresh1 fetch "$f" && 812c4d555d4Safresh1 verify "$f" || { 813eaf1d082Safresh1 integer e=$? 814eaf1d082Safresh1 8158e9ff1e6Safresh1 "$pending_status" && echo " failed." 816d60efbf6Safresh1 status " failed (${f##*/})" 8178e9ff1e6Safresh1 8188e9ff1e6Safresh1 if ((VERBOSE)) && [ -s "$FD_DIR/warn" ]; then 8198e9ff1e6Safresh1 cat "$FD_DIR/warn" >&2 8208e9ff1e6Safresh1 rm -f "$FD_DIR/warn" 821d60efbf6Safresh1 fi 822eaf1d082Safresh1 823eaf1d082Safresh1 # Fetch or verify exited > 1 824eaf1d082Safresh1 # which means we don't keep trying. 825eaf1d082Safresh1 ((e > 1)) && exit 1 826eaf1d082Safresh1 827c4d555d4Safresh1 continue 828c4d555d4Safresh1 } 82981b30a31Safresh1 fi 83081b30a31Safresh1 elif "$INSTALL"; then 831d60efbf6Safresh1 warn "Cannot install ${f##*/}, not found" 83281b30a31Safresh1 continue 83381b30a31Safresh1 fi 83481b30a31Safresh1 835d60efbf6Safresh1 if ! "$INSTALL"; then 836d60efbf6Safresh1 "$pending_status" && echo " done." 837d60efbf6Safresh1 continue 838d60efbf6Safresh1 fi 83981b30a31Safresh1 840d60efbf6Safresh1 if ! "$DRYRUN"; then 841d60efbf6Safresh1 if [ "$action" = Update ]; then 842d60efbf6Safresh1 for i in $( installed_firmware '' "$d-firmware-" '*' ) 843d60efbf6Safresh1 do 844d60efbf6Safresh1 delete_firmware "$i" || { 8458e9ff1e6Safresh1 "$pending_status" && 8468e9ff1e6Safresh1 echo -n " (remove $i failed)" 8478e9ff1e6Safresh1 status " (remove $i failed)" 8488e9ff1e6Safresh1 849d60efbf6Safresh1 continue 850d60efbf6Safresh1 } 8518e9ff1e6Safresh1 #status " (removed $i)" 85281b30a31Safresh1 done 85381b30a31Safresh1 fi 85481b30a31Safresh1 855d60efbf6Safresh1 add_firmware "$f" "$action" || { 8568e9ff1e6Safresh1 "$pending_status" && echo " failed." 857d60efbf6Safresh1 status " failed (${f##*/})" 858d60efbf6Safresh1 continue 859d60efbf6Safresh1 } 860c4d555d4Safresh1 fi 86181b30a31Safresh1 862d60efbf6Safresh1 if "$pending_status"; then 863d60efbf6Safresh1 if [ "$action" = Install ]; then 864d60efbf6Safresh1 echo " installed." 865c4d555d4Safresh1 else 866d60efbf6Safresh1 echo " updated." 867d60efbf6Safresh1 fi 86881b30a31Safresh1 fi 86981b30a31Safresh1done 87081b30a31Safresh1 871d60efbf6Safresh1[ "$unregister" ] && status "; unregister ${unregister:#,}" 872d60efbf6Safresh1[ "$kept" ] && status "; keep ${kept:#,}" 8735b80eddbSafresh1 8745b80eddbSafresh1exit 0 875