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

Alexey Gladkov gladkov.alexey at gmail.com
Tue Oct 26 22:03:44 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.

Я не понимаю, как эта фича будет работать с остальными. Например с luks
или fsck, которая может захотеть что-нибудь спросить и которая ничего из
этого не использует. Ты же не останавливаешь очень udev в ueventd. Поэтому
может вылезти любой диалог.

> 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


-- 
Rgrds, legion



More information about the Make-initrd mailing list