From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on sa.local.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM autolearn=ham autolearn_force=no version=3.4.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-transfer-encoding:content-language; bh=g2NrDjLCRuGUltQ74q0DcU+dRyrGwd/HdTy3ZMOVgQc=; b=BA4+zMxg19SUe0BYXVsiIsiWDLD+3X2WtmJvfFV4owb+3aHVbGprHL7oX8YOaEFKpe gpAFj7ke9qdSF7xeGLtvWhg/HbWJ6kHlURkv7jR7yHoUZhpyH2hKt58nWCWk6ZNRsCak 5duDDgOaXIlpU7pM/quHJmD7JzQHESFveFkaQusf1hPFXUSJZ4ew3kAv2cKECmHJ0FDg hXuH+egjcAqaVXdg2/OzNSj0Qhmt9tfij4zHUBN0apxzb0sE1PzQ50eVbOF8HbkTXhbR wq0rPTIgrS2WbMbHdmAJd9SK0O3CToDYVBFxJYAU5MvCf4Zv3NrF+4v4zFS0cFf4PF6Z rJHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-transfer-encoding :content-language; bh=g2NrDjLCRuGUltQ74q0DcU+dRyrGwd/HdTy3ZMOVgQc=; b=EGEPXaihESIeUrGTbkcTaMTNlrOv+6NTCesU4dQuNqhjSYuLk4QpBCrYJN9jNyGZW2 XL+8usWrfWyGdtnd6uzwdY87dQ9T57nUcffrK76Di5goG+L/gLRlRghu0bEu52tQG9cR NBJTbREnu3ATsvSQj02b+P4FthvXj5ejqvRnKho5AwUqvAzd4UouUXugvELM2zjhnWxQ HPdDlM/tPHHiTwWe5worxCbtcgYy9gzZsLA8M61ydlQv2e0Z9lZHepfkOx8lBq1KBsCQ UOI45VF0jjkYBAOA2+1qBWx9fKGasM2oN+z6iO5rorrAMVUU0wzMJIVTQNu4z19ffbBs lSMg== X-Gm-Message-State: AOAM530qvGyjdRA1/OnTajPD4I8ojFVvjK9iAMu+Qf4vJ4n9sAjJDHcR v7etkbJTFiuCq9WKjtbTrQPxE7m+zJw= X-Google-Smtp-Source: ABdhPJwCT/va7TyxTyvzDnir+Eqrjf9U7aElc0s2zyzJYb2TY0hw20XFuSa//tU759+RA8BBJ4ci8w== X-Received: by 2002:a2e:9446:: with SMTP id o6mr29170133ljh.455.1635278072550; Tue, 26 Oct 2021 12:54:32 -0700 (PDT) To: make-initrd@lists.altlinux.org References: <20211024172254.5CD94A5E20@lists.altlinux.org> <20211026185838.mnkahrx2v4ja34hf@example.org> From: Leonid Krivoshein Message-ID: <203cc85f-b12f-f3aa-1623-c6d958ef8e26@gmail.com> Date: Tue, 26 Oct 2021 22:54:31 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.8.0 MIME-Version: 1.0 In-Reply-To: <20211026185838.mnkahrx2v4ja34hf@example.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: ru Subject: Re: [make-initrd] [PATCH v6 18/22] bootchain-interactive: initial feature X-BeenThere: make-initrd@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: make-initrd@lists.altlinux.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Oct 2021 19:54:38 -0000 Archived-At: List-Archive: 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 >> --- >> 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 [ ???] >> +``` >> + >> +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 <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@lists.altlinux.org >> https://lists.altlinux.org/mailman/listinfo/make-initrd > -- Best regards, Leonid Krivoshein.