[make-initrd] [PATCH v6 18/22] bootchain-interactive: initial feature
Leonid Krivoshein
klark.devel at gmail.com
Sun Oct 24 20:22:53 MSK 2021
This feature adds the ability to use text dialogs in
the initramfs scripts. See README.md for more details.
Signed-off-by: Leonid Krivoshein <klark.devel at gmail.com>
---
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 <varname> <text> <label1> <item1> [<label2> <item2>â¦]
+```
+
+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 <title> <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
More information about the Make-initrd
mailing list