[make-initrd] [PATCH v6 18/22] bootchain-interactive: initial feature
Leonid Krivoshein
klark.devel at gmail.com
Tue Oct 26 22:54:31 MSK 2021
26.10.2021 21:58, Alexey Gladkov пишет:
> 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 или другой переменной из аргументов.
По идее, в $text, да и в других переменных тем более, не может быть
произвольного кода, так как это всё формируется в коде bootchain не на
основе вводимых данных. Однако, ...
> На самом деле тебе этот 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.
Ну да, там тогда почти во всём data/lib/IM-widgets/ это надо будет
переделать.
>> + 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
Да, эту идею я уже понял. Но, может, лучше с set?
$ text="..'; cat /etc/passwd; '.."
$ eval "v='$x'"
(уф, не буду показывать)!..
Это я к тому, что разве \" гарантирует невыполнение произвольного кода?
Я же мог и двойные кавычки использовать вместо одинарных:
$ text="..\"; cat /etc/passwd; \".."
$ eval "v=\"$x\""
(уф, тоже не буду показывать)!..
>> + 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
>
--
Best regards,
Leonid Krivoshein.
More information about the Make-initrd
mailing list