Sync prompt timeout code with sysupgrade watchdog
authorkn <kn@openbsd.org>
Sun, 29 Aug 2021 13:16:22 +0000 (13:16 +0000)
committerkn <kn@openbsd.org>
Sun, 29 Aug 2021 13:16:22 +0000 (13:16 +0000)
Simplify code and employ the same technique in both places.
The "prompt timeout" hits when on non-interactive installations or upgrades:

Welcome to the OpenBSD/amd64 6.9 installation program.
Starting non-interactive mode in 5 seconds...
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?
Performing non-interactive upgrade...

The existing code uses a regular background job and does quirky file
descriptor fiddling just to avoid job control messages when starting the
timeout in the background.

It also does `set +m' a second time for no reason and hardodes the number of
seconds in multiple places.

Do better by using a co-process just like sysupgrade's watchdog that reboots
when the upgrade did not finish in time.

reads good to aja

distrib/miniroot/dot.profile

index 93e6f58..6a998d9 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: dot.profile,v 1.46 2021/07/21 03:53:50 kn Exp $
+#      $OpenBSD: dot.profile,v 1.47 2021/08/29 13:16:22 kn Exp $
 #      $NetBSD: dot.profile,v 1.1 1995/12/18 22:54:43 pk Exp $
 #
 # Copyright (c) 2009 Kenneth R. Westerback
@@ -43,6 +43,23 @@ umask 022
 # emacs-style command line editing.
 set -o emacs
 
+TIMEOUT_PERIOD_SEC=5
+
+# Stop the background timer.
+stop_timeout() {
+       kill -KILL $WDPID 2>/dev/null
+}
+
+# Start a co-process to XXX.
+start_timeout() {
+       (
+               sleep $TIMEOUT_PERIOD_SEC && kill $$
+       ) |&
+       WDPID=$!
+
+       # Close standard input of the co-process.
+       exec 3>&p; exec 3>&-
+}
 
 if [[ -z $DONEPROFILE ]]; then
        DONEPROFILE=YES
@@ -78,30 +95,24 @@ __EOT
        # if netbooted or if a response file is found in / after a timeout,
        # but only the very first time around.
        timeout=false
-       timer_pid=
        if [[ ! -f /tmp/ai/noai ]] && { ifconfig netboot >/dev/null 2>&1 ||
                [[ -f /auto_install.conf ]] ||
                [[ -f /auto_upgrade.conf ]]; }; then
 
-               echo "Starting non-interactive mode in 5 seconds..."
+               echo "Starting non-interactive mode in ${TIMEOUT_PERIOD_SEC} seconds..."
                >/tmp/ai/noai
 
                # Set trap handlers to remove timer if the shell is interrupted,
                # killed or about to exit.
-               trap 'kill $timer_pid 2>/dev/null' EXIT
                trap 'exit 1' INT
                trap 'timeout=true' TERM
+               trap 'stop_timeout' EXIT
 
                # Stop monitoring background processes to avoid printing job
-               # completion notices in interactive shell mode. This doesn't
-               # stop the "[1] <pid>" on starting a job though; that's why
-               # stdout and stderr is redirected temporarily.
-               set +m
-               exec 3<&1 4<&2 >/dev/null 2>&1
-               (sleep 5; kill $$) &
-               timer_pid=$!
-               exec 1<&3 2<&4 3<&- 4<&-
+               # completion notices in interactive shell mode.
+               # Silence "[1] <pid>" on stderr when starting the timer.
                set +m
+               start_timeout 2>/dev/null
        fi
 
        while :; do
@@ -114,8 +125,7 @@ __EOT
                        REPLY=a
                else
                        # User has made a choice; stop the read timeout.
-                       [[ -n $timer_pid ]] && kill $timer_pid 2>/dev/null
-                       timer_pid=
+                       stop_timeout
                fi
 
                case $REPLY in