[make-initrd] [PATCH v6 18/22] bootchain-interactive: initial feature

Leonid Krivoshein klark.devel at gmail.com
Tue Oct 26 23:07:38 MSK 2021


26.10.2021 22:03, 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.
> Я не понимаю, как эта фича будет работать с остальными. Например с luks
> или fsck, которая может захотеть что-нибудь спросить и которая ничего из
> этого не использует. Ты же не останавливаешь очень udev в ueventd. Поэтому
> может вылезти любой диалог.

На текущий момент bootchain-interactive можно использовать какой-то 
одной фичей make-initrd, например, модулями bootchain. Именно по этой 
причине префикс bootchain пришлось пока оставить.

Очень хотелось бы эту ситуацию изменить, перетащить фичу на уровень 
выше, сделать её расшаренной между остальными фичами. Мы хотели обсудить 
воочию именно этот вопрос с тобой и Антоном. Если бы я знал, как это 
сделать, я бы давно сделал.

Потом, я уже говорил: эта "библиотека виджетов", равно как и вся 
концепция "IM", была сделана наспех только ради того, чтобы было просто 
и удобно рисовать виджеты в altboot. Тут есть что обсуждать и, наверное, 
переделывать в плане улучшения.


>> 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
>>
>> _______________________________________________
>> 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