[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