From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on sa.local.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FROM,MISSING_DATE,MISSING_MID, NML_ADSP_CUSTOM_MED,PP_MIME_FAKE_ASCII_TEXT autolearn=no autolearn_force=no version=3.4.1 From: "Leonid Krivoshein" To: make-initrd@lists.altlinux.org Subject: [make-initrd] [PATCH v6 18/22] bootchain-interactive: initial feature X-BeenThere: make-initrd@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: make-initrd@lists.altlinux.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Date: Sun, 24 Oct 2021 17:22:53 -0000 X-List-Received-Date: Sun, 24 Oct 2021 17:22:53 -0000 Message-ID: <20211024172253.obChBYRTxcfhdAFGmJBrnUajVYqEM3jpP4aC6cTe8Hg@z> Archived-At: List-Archive: This feature adds the ability to use text dialogs in the initramfs scripts. See README.md for more details. Signed-off-by: Leonid Krivoshein --- features/bootchain-interactive/README.md | 184 +++++++++++++ features/bootchain-interactive/config.mk | 5 + .../data/bin/activate-interactive-vt | 27 ++ .../data/bin/interactive-sh-functions | 247 ++++++++++++++++++ .../initrd/cmdline.d/bootchain-interactive | 3 + .../data/lib/IM-widgets/choice | 60 +++++ .../data/lib/IM-widgets/dlgmsg | 25 ++ .../data/lib/IM-widgets/errmsg | 29 ++ .../data/lib/IM-widgets/form | 70 +++++ .../data/lib/IM-widgets/gauge | 31 +++ .../data/lib/IM-widgets/ponder | 67 +++++ features/bootchain-interactive/rules.mk | 2 + 12 files changed, 750 insertions(+) create mode 100644 features/bootchain-interactive/README.md create mode 100644 features/bootchain-interactive/config.mk create mode 100755 features/bootchain-interactive/data/bin/activate-interactive-vt create mode 100644 features/bootchain-interactive/data/bin/interactive-sh-functions create mode 100644 features/bootchain-interactive/data/etc/initrd/cmdline.d/bootchain-interactive create mode 100644 features/bootchain-interactive/data/lib/IM-widgets/choice create mode 100644 features/bootchain-interactive/data/lib/IM-widgets/dlgmsg create mode 100644 features/bootchain-interactive/data/lib/IM-widgets/errmsg create mode 100644 features/bootchain-interactive/data/lib/IM-widgets/form create mode 100644 features/bootchain-interactive/data/lib/IM-widgets/gauge create mode 100644 features/bootchain-interactive/data/lib/IM-widgets/ponder create mode 100644 features/bootchain-interactive/rules.mk diff --git a/features/bootchain-interactive/README.md b/features/bootchain-interactive/README.md new file mode 100644 index 0000000..adb3de5 --- /dev/null +++ b/features/bootchain-interactive/README.md @@ -0,0 +1,184 @@ +# Feature: bootchain-interactive + +Feature adds the ability to use text dialogs in the initramfs scripts. + +## Boot parameters + +- `console=...` - Disable to switch TTY's, it useful for network/serial console. +- `noaskuser` - Disable all dialogs, it useful for console without user. +- `nolines` - Disable pseudo-graphics line drawing, it useful if not supported. + +## Synopsis +``` +. interactive-sh-functions +``` + +## Global variables + +- `$IM_BACKTITLE` - Back title for all input and output dialogs. +- `$IM_WIDGET_ARGS` - Additional arguments for `dialog` command. +- `$CONSOLE` - Non-empty value, if switching between TTY's are disabled. +- `$NOASKUSER` - Non-empty value, if all dialogs are disabled. +- `$NOLINES` - Non-empty value, if pseudo-graphics line drawing are disabled. + +## Briefly API + +- `IM_is_active()` - Returns 0, if interactive mode already activated. +- `IM_exec()` - Re-execute specified process on the foreground (tty2 by + default). +- `IM_activate()` - Request to immediately or delayed activation of the + interactive mode. +- `IM_load_widgets()` - Load specified widgets from the library. +- `IM_load_all()` - Load all available widgets from the library. +- `IM_start_output()` - Notify `interactive` feature about starting output. +- `IM_start_input()` - Notify `interactive` feature about starting intput. +- `IM_show_bootsplash()` - Show bootsplash such as plymoth and start the + progress bar. +- `IM_hide_bootsplash()` - Hide bootsplash such as plymoth and stop the + progress bar. +- `IM_update_bootsplash()` - Notify bootsplash such as plymoth about boot + state changes. + +## Widgets library + +Library is a scripts set, located in /lib/IM-widgets directory inside intitramfs +iamge. The base set can be extended. Before use input widgets, `IM_start_input()` +must be called, and `IM_start_output()` in otherwise. + +### choice (input) + +Display menu with one or more items, labels before items not displayed. +On success returns 0 and write choosen label to specified variable. Based +on `dialog --menu`. + +Syntax: +``` +IM_choice [ …] +``` + +Example: +``` +text="Please choose the installation method." + +while ! IM_choice method "$text" \ + nfs "NFS server" \ + ftp "FTP server" \ + http "HTTP server" \ + cifs "SAMBA server" \ + cdrom "CD-ROM Drive" \ + disk "Hard Disk Drive" \ + # +do + sleep 0.5 +done + +case "$method" in +nfs) +… +esac +``` + +### dlgmsg (input) + +Display text message. Always returns 0. Based on `dialog --msgbox`. + +Syntax: +``` +IM_dlgmsg <text> +``` + +Example: +``` +IM_dlgmsg "Live is success!" "$text" +``` + +### errmsg (input) + +Display error message. Always returns 0. Based on `dialog --msgbox`. + +Syntax: +``` +IM_errmsg <text> +``` + +Example: +``` +IM_errmsg "Disk read error, try again!" +``` + +### form (input) + +Display mixed data form. Input one or more text fields and store values +to specified varibales. Some variables associated with private data, +such as password, this input field characters outputs as asterics (`*`). +On success returns 0 and fill all variables by the entered values. +Based on `dialog --mixedform`. + +Syntax: +``` +IM_form <title> <text> <text-height> \ + <varname1> <fldlen1> <caption1> \ + [<varname2> <fldlen2> <caption2>…] +``` + +Example: +``` +IM_form "$title" "$text" 5 \ + server 64 "HTTP-server" \ + directory 128 "Directory" \ + || + continue +[ -n "$server" ] && [ -n "$directory" ] || + continue +``` + +### gauge (output) + +Display gauge (progress bar). Integer value from 0 to 100 must be sent +via stdin to specify displayed percent of the process passed. This is work +in conjuction with pv command. Always returns 0. Based on `dialog --gauge`. + +Note for `netconsole` usage: after process will finish, don't forget reset +the terminal, otherwise keyboard input will be lost. + +Syntax: +``` +echo <integer> | IM_gauge <title> [<text>] +``` + +Example: +``` +( for i in $(seq 1 10); do + echo "${i}0" + sleep 1 + done +) | IM_gauge "[ Loading... ]" + +[ -z "$CONSOLE" ] || + reset +``` + +### ponder (output) + +Displays the <waiting…> widget, which displays the undefined time of the +ongoing process, works independently of the main program code. The parameters +<delay> and <step> at startup determine by how many percent the thermometer +will automatically advance after a given time, i.e. set the frequency and +speed of the widget refresh. Always returns 0. Based on the `gauge` widget. + +Syntax: +``` +IM_ponder_start <title> [[[<text>] <delay>] <step>] +… +IM_ponder_stop +``` + +Example: +``` +IM_ponder_start "[ Scanning disk... ]" \ + "Searching random bits on the disk for fill CRNG entropy..." +find / -type f -print0 | + xargs -0 grep "Linus Torvalds" >/tmp/Linus.txt 2>/dev/null +rm -f /tmp/Linus.txt +IM_ponder_stop +``` diff --git a/features/bootchain-interactive/config.mk b/features/bootchain-interactive/config.mk new file mode 100644 index 0000000..69c8756 --- /dev/null +++ b/features/bootchain-interactive/config.mk @@ -0,0 +1,5 @@ +$(call feature-requires,depmod-image) + +BOOTCHAIN_INTERACTIVE_DATADIR = $(FEATURESDIR)/bootchain-interactive/data + +BOOTCHAIN_INTERACTIVE_PROGS = chvt dialog openvt pv diff --git a/features/bootchain-interactive/data/bin/activate-interactive-vt b/features/bootchain-interactive/data/bin/activate-interactive-vt new file mode 100755 index 0000000..90ae329 --- /dev/null +++ b/features/bootchain-interactive/data/bin/activate-interactive-vt @@ -0,0 +1,27 @@ +#!/bin/bash -efu + +. interactive-sh-functions + +delay="${1-}" + +IM_is_active || + fatal "interactive mode required" +exec </dev/null >/dev/null 2>&1 + +if [ -n "$delay" ]; then + while [ ! -f "${_IM_activated}" ]; do + [ "$delay" -gt 0 ] || + break + delay=$(( $delay - 1 )) + sleep 1 + done + sleep 1 +fi + +if [ ! -f "${_IM_activated}" ] && IM_is_active; then + :> "${_IM_activated}" + IM_hide_bootsplash + [ -n "$CONSOLE" ] || + chvt "${_IM_VT_number}" + rootdelay_pause +fi diff --git a/features/bootchain-interactive/data/bin/interactive-sh-functions b/features/bootchain-interactive/data/bin/interactive-sh-functions new file mode 100644 index 0000000..9baf3df --- /dev/null +++ b/features/bootchain-interactive/data/bin/interactive-sh-functions @@ -0,0 +1,247 @@ +#!/bin/bash -efu + +if [ -z "${__interactive_sh_functions-}" ]; then +__interactive_sh_functions=1 + +. /.initrd/initenv +. initrd-sh-functions + +. shell-signal + +message_time=1 + +# Public +IM_BACKTITLE= +IM_WIDGET_ARGS= +CONSOLE="${CONSOLE-}" +NOASKUSER="${NOASKUSER-}" +NOLINES="${NOLINES-}" + +# Internal +_IM_max_width= +_IM_widgetsdir=/lib/IM-widgets +_IM_flag=/.initrd/interactive-mode +_IM_unsplashed="${_IM_flag}/BOOTSPLASH-STOPPED" +_IM_activated="${_IM_flag}/VT-ACTIVATED" +_IM_VT_number="${_IM_VT_number:-2}" + +# Standart "reboot message" +IM_RBMSG="Press ENTER to reboot the computer..." + + +IM_is_active() +{ + [ -d "${_IM_flag}" ] || + return 1 +} + +IM_ponder_stop() +{ + : # Base implementation overrided in /lib/IM-widgets/ponder +} + +_IM_exit_handler() +{ + local rc=$? + + trap - EXIT + + if IM_is_active; then + IM_ponder_stop + rootdelay_unpause + if [ -z "$CONSOLE" ] && [ -z "$NOASKUSER" ]; then + clear + chvt 1 + fi + IM_show_bootsplash + rm -rf -- "${_IM_flag}" + fi + + exit $rc +} + +IM_exec() +{ + local now= + + if [ "${1-}" = "--now" ]; then + now=-s + shift + fi + + ! IM_is_active || + fatal "already in interactive mode" + + if [ -n "$CONSOLE" ] || [ -n "$NOASKUSER" ]; then + exec "$@" + else + [ -e "/dev/tty${_IM_VT_number}" ] || + mknod "/dev/tty${_IM_VT_number}" c 4 ${_IM_VT_number} + exec openvt -f -w $now -c${_IM_VT_number} -- "$@" + fi + + fatal "exec failed in IM_exec()" +} + +# shellcheck disable=SC2120 +IM_activate() +{ + local delay="${1-}" + local logfile="${2:-/var/log/IM.log}" + + ! IM_is_active || + fatal "already in interactive mode" + set_cleanup_handler _IM_exit_handler + + if [ -n "$NOASKUSER" ]; then + exec </dev/null >/dev/null 2>>"$logfile" + elif [ -n "$CONSOLE" ]; then + exec </dev/console >/dev/console 2>>"$logfile" + else + exec <"/dev/tty${_IM_VT_number}" >"/dev/tty${_IM_VT_number}" 2>>"$logfile" + fi + + mkdir -p -- "${_IM_flag}" + + export TERM="${TERM:-linux}" + export DIALOG_TTY=1 + export LC_ALL=C + export LANG=C + + # Determinating maximum width + if [ -n "$NOASKUSER" ]; then + _IM_max_width=80 + printf '%s\n' "${_IM_max_width}" >"${_IM_flag}/MAX-WIDTH" + elif [ -z "${_IM_max_width}" ]; then + local esc cols rows + + # The snippet above by Oleg Nesterov (C) was modified for IM, see: + # https://lists.altlinux.org/pipermail/make-initrd/2021-June/000458.html + # + echo -ne "\e[s\e[1000;1000H\e[6n\e[u" + # shellcheck disable=SC2162 + IFS=';[' read -s -t2 -dR esc rows cols || { + rows=24 + cols=80 + } + _IM_max_width=$(( $cols - 6 )) + stty rows "$rows" cols "$cols" 2>/dev/null ||: + printf '%s\n' "${_IM_max_width}" >"${_IM_flag}/MAX-WIDTH" + fi + + # Activating IM VT + if [ -n "$NOASKUSER" ]; then + message "TTY's not used, dialogs are disabled" + elif [ -n "$CONSOLE" ]; then + activate-interactive-vt + message "TTY's not available, using current system console" + elif [ -z "$delay" ]; then + activate-interactive-vt + message "TTY${_IM_VT_number} now active" + else + activate-interactive-vt "$delay" & + message "TTY${_IM_VT_number} will be activated after $((1 + $delay)) seconds" + fi + + # Warm up: back title do not displayed only with the first widget + # after openvt(), single dialog exec strangely solve this problem. + # + if [ -z "$CONSOLE" ] && [ -z "$NOASKUSER" ]; then + dialog ${NOLINES:+--ascii-lines} \ + --backtitle "WARM UP" \ + --title "[ Loading widgets ]" \ + --pause "" 7 40 0 \ + ||: + fi + + # Also we need to load and to check all widgets before using them + IM_load_all +} + +IM_load_widgets() +{ + local widget loaded + + for widget in "$@" _; do + [ -s "${_IM_widgetsdir}/$widget" ] || + continue + eval "loaded=\"\${__IM_${widget}_loaded-}\"" + + if [ -z "$loaded" ]; then + eval "__IM_${widget}_loaded=1" + . "${_IM_widgetsdir}/$widget" + fi + done +} + +IM_load_all() +{ + local widget + + # shellcheck disable=SC2045 + for widget in $(ls -- "${_IM_widgetsdir}/"); do + IM_load_widgets "$widget" + done +} + +IM_start_output() +{ + # shellcheck disable=SC2119 + IM_is_active || + IM_activate + [ -n "${_IM_max_width}" ] || + read -r _IM_max_width <"${_IM_flag}/MAX-WIDTH" || + _IM_max_width=66 + IM_load_widgets "$@" +} + +IM_start_input() +{ + [ -z "$NOASKUSER" ] || + fatal "input widgets not allowed, dialogs are disabled" + IM_start_output "$@" + [ -f "${_IM_activated}" ] || + activate-interactive-vt +} + +IM_show_bootsplash() +{ + local cmd=plymouth + + if IM_is_active && + [ -f "${_IM_unsplashed}" ] && + command -v $cmd >/dev/null && + $cmd --ping >/dev/null 2>&1 + then + $cmd unpause-progress --show-splash ||: + rm -f -- "${_IM_unsplashed}" + fi +} + +IM_hide_bootsplash() +{ + local cmd=plymouth + + if IM_is_active && + [ ! -f "${_IM_unsplashed}" ] && + command -v $cmd >/dev/null && + $cmd --ping >/dev/null 2>&1 + then + $cmd pause-progress --hide-splash ||: + :> "${_IM_unsplashed}" + fi +} + +IM_update_bootsplash() +{ + local cmd=plymouth + + if IM_is_active && + command -v $cmd >/dev/null && + $cmd --ping >/dev/null 2>&1 + then + $cmd update --status="$1" ||: + fi +} + +fi # __interactive_sh_functions diff --git a/features/bootchain-interactive/data/etc/initrd/cmdline.d/bootchain-interactive b/features/bootchain-interactive/data/etc/initrd/cmdline.d/bootchain-interactive new file mode 100644 index 0000000..8676770 --- /dev/null +++ b/features/bootchain-interactive/data/etc/initrd/cmdline.d/bootchain-interactive @@ -0,0 +1,3 @@ +register_parameter string CONSOLE +register_parameter bool NOASKUSER +register_parameter bool NOLINES diff --git a/features/bootchain-interactive/data/lib/IM-widgets/choice b/features/bootchain-interactive/data/lib/IM-widgets/choice new file mode 100644 index 0000000..23517e0 --- /dev/null +++ b/features/bootchain-interactive/data/lib/IM-widgets/choice @@ -0,0 +1,60 @@ +#!/bin/bash -efu + +IM_choice() +{ + IM_start_input + + local varname="$1" text="${2:-\n}"; shift 2 + local height=1 width=$(( 4 + ${#text} )) + local rc=0 items=$(( $# / 2 )) + + _calculate_items_width() + { + local label iw i=0 + + while [ $i -lt $items ]; do + label="$2"; shift 2 + iw=$(( 4 + ${#label} )) + [ $iw -le $width ] || + width=$iw + i=$((1 + $i)) + done + } + + [ $items -gt 0 ] || + return 1 + [ $width -gt "${_IM_max_width}" ] || + _calculate_items_width "$@" + if [ $width -lt 40 ]; then + width=40 + elif [ $width -gt ${_IM_max_width} ]; then + height=$(( $width / ${_IM_max_width} + 1 )) + width=${_IM_max_width} + fi + if [ $items -gt 7 ]; then + height=$((14 + $height)) + else + height=$((7 + $height + $items)) + fi + + local dlgcmd="dialog $IM_WIDGET_ARGS ${NOLINES:+--ascii-lines}" + dlgcmd="$dlgcmd ${IM_BACKTITLE:+--backtitle \"$IM_BACKTITLE\"}" + dlgcmd="$dlgcmd --title \"[ Please choose... ]\"" + dlgcmd="$dlgcmd --no-tags --menu \"\n$text\"" + dlgcmd="$dlgcmd $height $width $items" + + while [ $# -ge 2 ]; do + dlgcmd="$dlgcmd \"$1\" \"$2\"" + shift 2 + done + + exec 3>&1 + text="$(eval "$dlgcmd" 2>&1 1>&3)" || rc=$? + exec 3>&- + + [ -z "$CONSOLE" ] || + reset + [ $rc -eq 0 ] || + return $rc + eval "$varname=\"$text\"" +} diff --git a/features/bootchain-interactive/data/lib/IM-widgets/dlgmsg b/features/bootchain-interactive/data/lib/IM-widgets/dlgmsg new file mode 100644 index 0000000..74e1eba --- /dev/null +++ b/features/bootchain-interactive/data/lib/IM-widgets/dlgmsg @@ -0,0 +1,25 @@ +#!/bin/bash -efu + +IM_dlgmsg() +{ + IM_start_input + + local title="$1" text="$2" height=2 + local width=$(( 4 + ${#text} )) + + if [ $width -lt 40 ]; then + width=40 + elif [ $width -gt ${_IM_max_width} ]; then + height=$(( $width / ${_IM_max_width} + 2 )) + width=${_IM_max_width} + fi + + dialog $IM_WIDGET_ARGS \ + ${NOLINES:+--ascii-lines} \ + ${IM_BACKTITLE:+--backtitle "$IM_BACKTITLE"} \ + --title "$title" \ + --msgbox "\n$text" \ + $((4 + $height)) $width ||: + [ -z "$CONSOLE" ] || + reset +} diff --git a/features/bootchain-interactive/data/lib/IM-widgets/errmsg b/features/bootchain-interactive/data/lib/IM-widgets/errmsg new file mode 100644 index 0000000..e5f05db --- /dev/null +++ b/features/bootchain-interactive/data/lib/IM-widgets/errmsg @@ -0,0 +1,29 @@ +#!/bin/bash -efu + +IM_errmsg() +{ + IM_start_input + + local text="$1" height=2 + local width=$(( 4 + ${#text} )) + + if [ $width -lt 40 ]; then + width=40 + elif [ $width -gt ${_IM_max_width} ]; then + height=$(( $width / ${_IM_max_width} + 2 )) + width=${_IM_max_width} + fi + + [ ! -s /etc/dialogrc.error ] || + export DIALOGRC=/etc/dialogrc.error + dialog $IM_WIDGET_ARGS \ + ${NOLINES:+--ascii-lines} \ + ${IM_BACKTITLE:+--backtitle "$IM_BACKTITLE"} \ + --title "[ Error! ]" \ + --msgbox "\n$text" \ + $((4 + $height)) $width ||: + [ -z "$CONSOLE" ] || + reset + [ ! -s /etc/dialogrc.error ] || + export DIALOGRC= +} diff --git a/features/bootchain-interactive/data/lib/IM-widgets/form b/features/bootchain-interactive/data/lib/IM-widgets/form new file mode 100644 index 0000000..0c8c98e --- /dev/null +++ b/features/bootchain-interactive/data/lib/IM-widgets/form @@ -0,0 +1,70 @@ +#!/bin/bash -efu + +IM_form() +{ + IM_start_input + + local i=0 lw=0 formHeight=$(( $# / 3 - 1 )) + local title="$1" text="$2" textHeight="$3" + local label varname ilen itype; shift 3 + + _calculate_labels_width() + { + while [ $i -lt $formHeight ]; do + label="$3"; shift 3 + [ ${#label} -le $lw ] || + lw=${#label} + i=$((1 + $i)) + done + } + + [ $formHeight -gt 0 ] || + return 1 + [ -n "$title" ] || + title="[ Please fill entries... ]" + _calculate_labels_width "$@" + lw=$((4 + $lw)); i=1 + + local width=60 rc=0 vars="" values="" + local height=$((7 + $textHeight + $formHeight)) + local fieldWidth=$(( $width - $lw - 6 )) + + local dlgcmd="dialog $IM_WIDGET_ARGS ${NOLINES:+--ascii-lines}" + dlgcmd="$dlgcmd ${IM_BACKTITLE:+--backtitle \"$IM_BACKTITLE\"}" + dlgcmd="$dlgcmd --insecure --title \"$title\"" + dlgcmd="$dlgcmd --mixedform \"\n$text\"" + dlgcmd="$dlgcmd $height $width $formHeight" + + while [ $i -le $formHeight ]; do + varname="$1" + ilen="$2" + label="$3" + shift 3 + itype=0 + case "$varname" in + password*|passwd*|pass|pass1|pass2) + itype=1 + ;; + esac + vars="${vars}${varname} " + dlgcmd="$dlgcmd \"$label:\" $i 1 \"\${$varname}\"" + dlgcmd="$dlgcmd $i $lw $fieldWidth $ilen $itype" + i=$((1 + $i)) + done + + exec 3>&1 + values=$(eval "$dlgcmd" 2>&1 1>&3) || rc=$? + exec 3>&- + + [ -z "$CONSOLE" ] || + reset + [ "$rc" = 0 ] || + return $rc + i=1 + while [ "$i" -le "$formHeight" ]; do + varname="$(echo "$vars" |cut -f$i -d ' ')" + rc="$(echo "$values" |sed -n -r ${i}p)" + eval "$varname=\"$rc\"" + i=$((1 + $i)) + done +} diff --git a/features/bootchain-interactive/data/lib/IM-widgets/gauge b/features/bootchain-interactive/data/lib/IM-widgets/gauge new file mode 100644 index 0000000..baf7ac5 --- /dev/null +++ b/features/bootchain-interactive/data/lib/IM-widgets/gauge @@ -0,0 +1,31 @@ +#!/bin/bash -efu + +IM_gauge() +{ + IM_start_output + + local title="$1" text="${2-}" + local height=1 width=$(( 4 + ${#text} )) + + if [ $width -gt ${_IM_max_width} ]; then + height=$(( $width / ${_IM_max_width} + 1 )) + width=${_IM_max_width} + elif [ $width -lt 40 ]; then + [ $width -ne 4 ] || + height=0 + width=40 + fi + + if [ -n "$text" ]; then + height=$((1 + $height)) + text="\n$text" + fi + + dialog $IM_WIDGET_ARGS \ + ${NOLINES:+--ascii-lines} \ + ${IM_BACKTITLE:+--backtitle "$IM_BACKTITLE"} \ + --title "$title" \ + --gauge "$text" \ + $((5 + $height)) $width 2>/dev/null \ + ||: +} diff --git a/features/bootchain-interactive/data/lib/IM-widgets/ponder b/features/bootchain-interactive/data/lib/IM-widgets/ponder new file mode 100644 index 0000000..c6d4600 --- /dev/null +++ b/features/bootchain-interactive/data/lib/IM-widgets/ponder @@ -0,0 +1,67 @@ +#!/bin/bash -efu + +# Internal +_IM_ponder_pid= +_IM_ponder_finished="${_IM_flag}/PONDER-FINISHED" + +_IM_ponder_bg() +{ + local dlgcmd="IM_gauge \"$1\" \"$2\"" + local delay="$3" step="$4" percent=0 forward=1 + + ( while [ ! -f "${_IM_ponder_finished}" ]; do + echo "$percent" + + if [ $forward -ne 0 ]; then + if [ $percent -lt 100 ]; then + percent=$(( $percent + $step )) + else + percent=$(( $percent - $step )) + forward=0 + fi + else + if [ $percent -gt 0 ]; then + percent=$(( $percent - $step )) + else + percent=$(( $percent + $step )) + forward=1 + fi + fi + + [ $percent -le 100 ] || + percent=100 + [ $percent -ge 0 ] || + percent=0 + sleep "$delay" + done + + echo "100" + ) |eval "$dlgcmd" +} + +IM_ponder_start() +{ + IM_start_output gauge + + local title="$1" text="${2-}" + local delay="${3:-0.5}" + local step="${4:-10}" + + [ -z "${_IM_ponder_pid}" ] || + return 0 + rm -f -- "${_IM_ponder_finished}" + _IM_ponder_bg "$title" "$text" "$delay" "$step" & + _IM_ponder_pid=$! +} + +IM_ponder_stop() +{ + [ -n "${_IM_ponder_pid}" ] || + return 0 + :> "${_IM_ponder_finished}" + wait "${_IM_ponder_pid}" 2>/dev/null ||: + rm -f -- "${_IM_ponder_finished}" + [ -z "$CONSOLE" ] || + reset + _IM_ponder_pid= +} diff --git a/features/bootchain-interactive/rules.mk b/features/bootchain-interactive/rules.mk new file mode 100644 index 0000000..b647caf --- /dev/null +++ b/features/bootchain-interactive/rules.mk @@ -0,0 +1,2 @@ +PUT_FEATURE_DIRS += $(BOOTCHAIN_INTERACTIVE_DATADIR) +PUT_FEATURE_PROGS += $(BOOTCHAIN_INTERACTIVE_PROGS) -- 2.24.1