Download raw body.
Better SIGINFO for fw_update(8)
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
Better SIGINFO for fw_update(8)