[make-initrd] [PATCH v6 18/22] bootchain-interactive: initial feature
Alexey Gladkov
gladkov.alexey at gmail.com
Tue Oct 26 21:58:38 MSK 2021
On Sun, Oct 24, 2021 at 08:22:54PM +0300, Leonid Krivoshein wrote:
> 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=$?
Вот этим eval ты запросто можешь выполнить любой произвольный код из
$text или другой переменной из аргументов. На самом деле тебе этот eval не
нужен, если аккуратно заполнить свои же аргументы:
set -- $IM_WIDGET_ARGS \
${NOLINES:+--ascii-lines} \
${IM_BACKTITLE:+--backtitle "$IM_BACKTITLE"} \
--title "[ Please choose... ]" \
--no-tags --menu "\n$text" \
$height $width $items \
"$@"
text="$(dialog "$@" 2>&1 1>&3)" || rc=$?
Ну а можно и как ниже вообще без set сразу dialog передавать аргументы.
> + exec 3>&-
> +
> + [ -z "$CONSOLE" ] ||
> + reset
> + [ $rc -eq 0 ] ||
> + return $rc
> + eval "$varname=\"$text\""
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=$?
Тоже самое что и в IM_choice.
> + 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\""
eval "$varname=\"\$rc\""
^
$ echo $HOME
/home/legion
$ text='$HOME'
$ eval "v=\"$text\""
$ echo $v
/home/legion
$ eval "v=\"\$text\""
$ echo $v
$HOME
> + 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"
А тут зачем eval если это IM_gauge "$1" "$2" ?
> +}
> +
> +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
>
> _______________________________________________
> Make-initrd mailing list
> Make-initrd at lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/make-initrd
--
Rgrds, legion
More information about the Make-initrd
mailing list