From: Andrew Hewus Fresh Subject: Better SIGINFO for fw_update(8) To: tech@openbsd.org Date: Sun, 26 Oct 2025 15:24:57 -0700 Theo mentioned that sometimes fw_update takes a while and sending a SIGINFO doesn't provide anthing useful. Unfortunately, because when VERBOSE < 2 we save ftp output for later it's not super straight forward. Saving the partially output lines so we can print them again after the info was also a bit challenging, but it looks much nicer. Hopefully we don't get a partially truncated INFO output in that case, but I'm not sure how to guarantee that. One issue is that I am not sure what is catching the SIGINFO and printing "load: 0.19 cmd: ksh 97111 [running] 0.02u 0.04s 0% 190k", but I haven't looked terribly hard. `trap "" INFO` doesn't stop it though. Right now we it only traps during "fetch", but we could add another more global handler and variable that prints out like "Install whatever-firmware" or "Remove whatever" if it were useful. Comments, suggestions (especially on the "load:..." output), OK? Index: fw_update.sh =================================================================== RCS file: /cvs/src/usr.sbin/fw_update/fw_update.sh,v diff -u -p -r1.65 fw_update.sh --- fw_update.sh 12 May 2025 23:48:12 -0000 1.65 +++ fw_update.sh 26 Oct 2025 22:21:28 -0000 @@ -46,8 +46,11 @@ unset FWPKGTMP REMOVE_LOCALSRC=false DROP_PRIVS=true -status() { echo -n "$*" >&"$STATUS_FD"; } -warn() { echo "$*" >&"$WARN_FD"; } +status() { + [ ! "${FD_DIR:-}" ] || echo -n "$*" >> "$FD_DIR/last_status" + echo -n "$*" >&"$STATUS_FD" +} +warn() { echo "$*" >&"$WARN_FD"; } cleanup() { set +o errexit # ignore errors from killing ftp @@ -101,6 +104,41 @@ spin() { }>/dev/tty } +ftp_info() { + local _src="$1" _ftp_errors="$2" + local _timeout=30 # tenths of a second + + # For some reason, I can't trap INFO so it always outputs "load ...", + # so we don't need to output a newline before the INFO. + # [ ! "${FD_DIR:-}" ] || [ ! -s "$FD_DIR/last_status" ] || echo "" + + echo "Fetching $_src" >&2 + + kill -INFO -"$FTPPID" 2>/dev/null || return 0 + + # If VERBOSE is than 2, we are storing its STDERR in _ftp_errors, + # and we need special handling, otherwise it outputs as normal. + (( VERBOSE < 2 )) || return 0 + + # However, ftp should normally have be quiet until it + # prints INFO so give it up to three seconds to do that. + # If we don't get info in three seconds, let them try again. + while [ ! -s "$_ftp_errors" ]; do + (( _timeout-- > 0 )) || return 0 + sleep 0.1 + done + + # Output the info and truncate so we can print additional output later + cat "$_ftp_errors" >&2 + >|"$_ftp_errors" + + # Re-print the last_status so the line looks right. + [ ! "${FD_DIR:-}" ] || [ ! -s "$FD_DIR/last_status" ] || + cat "$FD_DIR/last_status" + + return 0 +} + fetch() { local _src="${FWURL}/${1##*/}" _dst=$1 _user=_file _exit _error='' local _ftp_errors="$FD_DIR/ftp_errors" @@ -127,6 +165,8 @@ fetch() { ) & FTPPID=$! set +o monitor + trap 'ftp_info "$_src" "$_ftp_errors"' INFO + SECONDS=0 _last=0 while kill -0 -"$FTPPID" 2>/dev/null; do @@ -150,6 +190,7 @@ fetch() { _exit=$? set -o errexit + trap - INFO unset FTPPID if ((_exit != 0)); then @@ -764,24 +805,28 @@ if [ "${devices[*]:-}" ]; then if "$verify_existing" && [ -e "$f" ]; then pending_status=false if ((VERBOSE == 1)); then - echo -n "Verify ${f##*/} ..." + echo -n "Verify ${f##*/} ..." | + tee "$FD_DIR/last_status" pending_status=true elif ((VERBOSE > 1)) && ! "$INSTALL"; then echo "Keep/Verify ${f##*/}" fi if "$DRYRUN" || verify_existing "$f"; then - "$pending_status" && echo " done." + "$pending_status" && echo " done." && + rm -f "$FD_DIR/last_status" if ! "$INSTALL"; then kept="$kept,$d" continue fi elif "$DOWNLOAD"; then - "$pending_status" && echo " failed." + "$pending_status" && echo " failed." && + rm -f "$FD_DIR/last_status" ((VERBOSE > 1)) && echo "Refetching $f" rm -f "$f" else - "$pending_status" && echo " failed." + "$pending_status" && echo " failed." && + rm -f "$FD_DIR/last_status" continue fi fi @@ -831,7 +876,8 @@ for f in "${add[@]}" _update_ "${update[ ((VERBOSE)) && echo "$action ${f##*/}" else if ((VERBOSE == 1)); then - echo -n "Install ${f##*/} ..." + echo -n "Install ${f##*/} ..." | + tee "$FD_DIR/last_status" pending_status=true fi fi @@ -840,14 +886,16 @@ for f in "${add[@]}" _update_ "${update[ ((VERBOSE)) && echo "Get/Verify ${f##*/}" else if ((VERBOSE == 1)); then - echo -n "Get/Verify ${f##*/} ..." + echo -n "Get/Verify ${f##*/} ..." | + tee "$FD_DIR/last_status" pending_status=true fi fetch "$f" && verify "$f" || { integer e=$? - "$pending_status" && echo " failed." + "$pending_status" && echo " failed." && + rm -f "$FD_DIR/last_status" status " failed (${f##*/})" if ((VERBOSE)) && [ -s "$FD_DIR/warn" ]; then @@ -868,7 +916,8 @@ for f in "${add[@]}" _update_ "${update[ fi if ! "$INSTALL"; then - "$pending_status" && echo " done." + "$pending_status" && echo " done." && + rm -f "$FD_DIR/last_status" continue fi @@ -888,7 +937,8 @@ for f in "${add[@]}" _update_ "${update[ fi add_firmware "$f" "$action" || { - "$pending_status" && echo " failed." + "$pending_status" && echo " failed." && + rm -f "$FD_DIR/last_status" status " failed (${f##*/})" continue } @@ -900,6 +950,7 @@ for f in "${add[@]}" _update_ "${update[ else echo " updated." fi + rm -f "$FD_DIR/last_status" fi done