From patchwork Mon Apr 27 06:39:55 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kasturi shekar X-Patchwork-Id: 5051 Return-Path: Received: from shymkent.ilbers.de ([unix socket]) by shymkent (Cyrus 2.5.10-Debian-2.5.10-3+deb9u2) with LMTPA; Mon, 27 Apr 2026 08:40:16 +0200 X-Sieve: CMU Sieve 2.4 Received: from mail-qt1-f185.google.com (mail-qt1-f185.google.com [209.85.160.185]) by shymkent.ilbers.de (8.15.2/8.15.2/Debian-8+deb9u1) with ESMTPS id 63R6e8Sd000479 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Mon, 27 Apr 2026 08:40:08 +0200 Received: by mail-qt1-f185.google.com with SMTP id d75a77b69052e-50fb3c7b989sf109490711cf.0 for ; Sun, 26 Apr 2026 23:40:08 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1777272002; cv=pass; d=google.com; s=arc-20240605; b=K/yghsedggJTTDzIID4QGQYUibGS3+dfq+z16cP997DP7iWeNXsnbDbf5KmOjsd7k/ S2zJbggvPkHmbFokxC82Rspdp8EtrAY7ofP52hxz4VpKx8QFkS+66T+Ot2aqxyefBNMs MiwuQAmTF6NNDPZFtS0RwxJ/sh3dYsMXKbZOeGdeFzXyBLT1M5cH69XRvs/teW+ODlca 98yLY4pxP2gMqjiUT2UGmmB5600D4qf/Lu6DXnE9UUqO0H1FiIFSbo0TpEvF+LMOftAE nuzuy6IHje+M8rq/cjcrVQ9WRxYehpq0ekflNtckKo50RzqXuI9ke+HGoaY7vP7MJn0G 8Ssg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:feedback-id:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=VTmvnn9fk1Dwikgezeh1dpRzaynQwmGZt2UmqtKKsAg=; fh=l4IMEeLuV5xWGoG4sdw6xQKfmhA3Urt4UULBBYMXYz4=; b=T32ihCdLn9cOO3JZB0JTCw24Vkx7avQzZqS9lViWWHYct/dcCtxNB/PLPlIZLBTbqM m8dMsWCzVyyrJBqZJLHKipU5b2qZW8h8MdK+FbKN0xdOPoEKrp6o/H2NPuqZPKV9jJ6h UfQCo6sYdR3qI+BwR2Ya9ZZqqJ5/Zx9fmTTkTnldfVkGu7bmfkpXMPiaEvaHBfxzmjuK CT04XH0ptIhvOQQeQTFNiiogizAG8Dw1hO9kyjEam677j1kjAz1WYMg64QvvSNlOQNzM f6pnzkEb7RHMke+1r5CNWuK98H4bynxIktFkj9h7FzOjtM5Nl5ha9hOu25IWlS31Q00I Zhbw==; darn=isar-build.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=fm2 header.b=O1QuGWLa; spf=pass (google.com: domain of fm-1328757-20260427064000a9a8877af0000207a7-4x_blb@rts-flowmailer.siemens.com designates 185.136.64.228 as permitted sender) smtp.mailfrom=fm-1328757-20260427064000a9a8877af0000207a7-4X_BlB@rts-flowmailer.siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1777272002; x=1777876802; darn=isar-build.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:feedback-id :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:from:to:cc:subject:date:message-id:reply-to; bh=VTmvnn9fk1Dwikgezeh1dpRzaynQwmGZt2UmqtKKsAg=; b=GBESgh6ifJl/oBxQIaPz9oZnr2CXeipY4Xhx72Rjp+K9nIZDC27tqylRaSfeALokvQ 7hPaqK20gMUSyvTdM+mM3Xo/6AUUVVpgX7PzjN8/4pPgamwmh5v+T5VgRX4vkrG6/+QV qtBgQ1so6ExRj/DY9fG0IKRhOdO+Gol2TCgDN1HNzlSgfpSsokUxyVsvxnD/rO0QoA0Q IeQOBl5h2ceVrioeszQY404JlNzCt03qHvxBaIe1pXw7Q44kURGMPVND+y6abdrOBYnK H0QsM+ICr8LVKJPQqL2rmcLaUmgi/5HYxASNAsA4wqKjprTHlMqFAS7D6wtWGd7e/HdI BNiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777272002; x=1777876802; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:feedback-id :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:x-beenthere:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=VTmvnn9fk1Dwikgezeh1dpRzaynQwmGZt2UmqtKKsAg=; b=ZI0qEdEGyKMcP8p7cSMAT8Z3/0U4jlBmowhmTP1qESoTTgpenLYvOKoqtAbB2mgtBC ho1xqV4tRn/iNXEwa1fyFZ8H7ZHMz7Io+5kKaHhFVDzepHqcAtZVKupX2IDoVM5U1i+e qiVt/LthvwzQsnJQePRGZbBMnwWLgIa7EJXPGXPaJJdAg1bB+XcORxQJKqVGLT2lY5eJ Z6NeNPMIjEhtkbLtCj/qYsF/esdSIO3jmpTFt293T8jT/CqQ3MyMR6y+OqYUimXN+/DW 3DZBMQiRoR6AOnam7w+cXFshJlTWvmofTB54JIF8Tnc9nPdTwM2xBTma4H3eEaRdcbJR gepA== X-Forwarded-Encrypted: i=2; AFNElJ8AoFDblpQ8a1ScgyHUdcKquf/rgNFOuNCgjqt5eITXmt/AUXhHnsrFOAeE1WVLdGn516XpYQI=@isar-build.org X-Gm-Message-State: AOJu0YzsDQmsBPVHOK64Ln598+GGNvjuhDrOu1gwb7MALkMBzxiMHa/s eguNrgSWPeJPacbbulQzHWFh47IVSCxs4T5Y04zPZsaEkwkubk10blGe X-Received: by 2002:ac8:5856:0:b0:50f:ca25:fb48 with SMTP id d75a77b69052e-50fca26036fmr264083651cf.55.1777272002342; Sun, 26 Apr 2026 23:40:02 -0700 (PDT) X-BeenThere: isar-users@googlegroups.com; h="AYAyTiKkUQdWhe2zEXsmQg3JvxpmEs0d8Mn0S7TcWA0DGxS/xA==" Received: by 2002:ac8:628a:0:b0:50e:5a4b:401c with SMTP id d75a77b69052e-50e5a4b5477ls79181981cf.0.-pod-prod-01-us; Sun, 26 Apr 2026 23:40:01 -0700 (PDT) X-Received: by 2002:a05:622a:287:b0:50f:b4c0:62ff with SMTP id d75a77b69052e-50fb4c068famr393703881cf.54.1777272001398; Sun, 26 Apr 2026 23:40:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1777272001; cv=none; d=google.com; s=arc-20240605; b=Uao0nJGKGRNGIPiGZc2i+g5u8EsSz5Nfqaz+ClHo8gclLPfVY9cjyEUgq7QpPj7CPe Y5wfXUSmvsKT8EBrkFnalvj2oaCsMRHXweClW4ZfXrzKq/nDTIbbKPKFemoLwqxx9lUr eioXW3D51LG/4NAnS7VAGIrLVwT8HUXk97mHIy203ufCz+U0UdVl+PqdD/jgSmsaLK2W P+OuYnRLk4ON2lxy3hB7iuUmhHOFhU3ArueH71g+SL2Zx603LVEZ3VEc5fEWhHyKWytn Xk0Zk7vwYlsWgXckrgZcL5rXy7r5mzR3yK2tB/eUoiHjfXZT+lzBveVXzruRsI+tLD5y dm7A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=feedback-id:content-transfer-encoding:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature; bh=0mWN3zvhbc/yCMVJqXHPqNT0BJg7H4y5py8KuQ+bIP0=; fh=kh6mBxUBxYhzFhhtG3ckYICU9JWCX223LZXZsw4oG5w=; b=icxTaKNyqFA1XTF8MiGFgSyzk/79hpqsH2wFDSOF/BPW4Q+xDhRPSIO2XclQBGb6g/ MRVTrGVZD4JwCQfJsmcDYoH/nQGcImo237CKiYXB6nvUF5LESpHTm3YeO6cVke9n3J23 11xOXKOgDy6uvlV3u7QlWN5kBIwe8yBGg/YW/OBfzHas3gPjZLPqYJQgE/7PKKgqP8m/ 3mmikcb6yVUkgoaxeIhSpZxICP4yrnTI9a4bamHKxDDhHC0TRH7joMw1QCbvVi4evVkl CkR0dscJQNjJvtap7KR1mLwxDeDnpAfaHF+cd8xsW0ogtr67eP3gknlrfTfJWJuCSbnE Dz+A==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=fm2 header.b=O1QuGWLa; spf=pass (google.com: domain of fm-1328757-20260427064000a9a8877af0000207a7-4x_blb@rts-flowmailer.siemens.com designates 185.136.64.228 as permitted sender) smtp.mailfrom=fm-1328757-20260427064000a9a8877af0000207a7-4X_BlB@rts-flowmailer.siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com Received: from mta-64-228.siemens.flowmailer.net (mta-64-228.siemens.flowmailer.net. [185.136.64.228]) by gmr-mx.google.com with ESMTPS id d75a77b69052e-50fbe8b5d39si6680961cf.4.2026.04.26.23.40.01 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 26 Apr 2026 23:40:01 -0700 (PDT) Received-SPF: pass (google.com: domain of fm-1328757-20260427064000a9a8877af0000207a7-4x_blb@rts-flowmailer.siemens.com designates 185.136.64.228 as permitted sender) client-ip=185.136.64.228; Received: by mta-64-228.siemens.flowmailer.net with ESMTPSA id 20260427064000a9a8877af0000207a7 for ; Mon, 27 Apr 2026 08:40:01 +0200 X-Patchwork-Original-From: "'Kasturi shekar' via isar-users" From: Kasturi shekar To: isar-users@googlegroups.com Cc: "kasturi.shekar" Subject: [PATCH 3/4] installer: add installer flow module and entrypoint Date: Mon, 27 Apr 2026 12:09:55 +0530 Message-ID: <20260427063957.603123-4-kasturi.shekar@siemens.com> In-Reply-To: <20260427063957.603123-1-kasturi.shekar@siemens.com> References: <20260427063957.603123-1-kasturi.shekar@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-1328757:519-21489:flowmailer X-Original-Sender: kasturi.shekar@siemens.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@siemens.com header.s=fm2 header.b=O1QuGWLa; spf=pass (google.com: domain of fm-1328757-20260427064000a9a8877af0000207a7-4x_blb@rts-flowmailer.siemens.com designates 185.136.64.228 as permitted sender) smtp.mailfrom=fm-1328757-20260427064000a9a8877af0000207a7-4X_BlB@rts-flowmailer.siemens.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=siemens.com X-Original-From: Kasturi shekar Reply-To: Kasturi shekar Precedence: list Mailing-list: list isar-users@googlegroups.com; contact isar-users+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: isar-users@googlegroups.com X-Google-Group-Id: 914930254986 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Status: No, score=-4.9 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, RCVD_IN_RP_CERTIFIED,RCVD_IN_RP_RNBL,RCVD_IN_RP_SAFE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on shymkent.ilbers.de X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= From: "kasturi.shekar" high-level orchestration and keep deploy-image-wic.sh as a thin launcher. This keeps the externally used script name stable while making the flow easier to review and maintain by separating: - backend APIs - UI frontend - mode/orchestration flow Signed-off-by: kasturi.shekar --- .../files/usr/bin/deploy-image-wic.sh | 475 +++++++----------- 1 file changed, 192 insertions(+), 283 deletions(-) mode change 100755 => 100644 meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh diff --git a/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh b/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh old mode 100755 new mode 100644 index 60944e58..d128a9b8 --- a/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh +++ b/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # This software is a part of Isar. -# Copyright (C) Siemens AG, 2024 +# Copyright (C) Siemens AG, 2026 # # SPDX-License-Identifier: MIT @@ -9,293 +9,202 @@ installdata=${INSTALL_DATA:-/install} SCRIPT_DIR=$( dirname -- "$( readlink -f -- "$0"; )"; ) . "${SCRIPT_DIR}/../lib/deploy-image-wic/handle-config.sh" +. "${SCRIPT_DIR}/sys_api.sh" +. "${SCRIPT_DIR}/installer_ui.sh" -if [ "$installer_unattended" = true ] && [ "$installer_unattended_abort_enable" = true ]; then - abort_file=/tmp/attended_mode_trigger - for ((i=$installer_unattended_abort_timeout; i>0; i--)); do - echo -ne "\rUnattended installation will start in $i seconds. Press any key to switch to attended mode..." +#-------------------------------------------------------------------------- +# This module contains high-level installer flow logic +# while keeping low-level backend APIs in sys_api.sh +# and user-facing dialogs in installer_ui.sh. +#-------------------------------------------------------------------------- - # Switch to attended mode if the abort file exists or any key pressed during countdown - # Create abort file to notify all other console instances to abort - if [ -f "$abort_file" ] || read -n 1 -t 1; then - installer_unattended=false - touch "$abort_file" - break - fi - done -fi - -if ! $installer_unattended; then - installer_image_uri=$(find "$installdata" -type f -iname "*.wic*" -a -not -iname "*.wic.bmap" -exec basename {} \;) - if [ -z "$installer_image_uri" ] || [ ! -f "$installdata/$installer_image_uri" ]; then - pushd "$installdata" - for f in $(find . -type f ! -iname "*.wic.bmap"); do - array+=("$f" "$f") - done - popd - if [ ${#array[@]} -gt 0 ]; then - if ! installer_image_uri=$(dialog --no-tags \ - --menu "Select image to be installed" 10 60 3 \ - "${array[@]}" --output-fd 1); then - exit 0 - fi - fi - fi - - if [ ! -f "$installdata/$installer_image_uri" ]; then - dialog --msgbox "Could not find an image to install. Installation aborted." 6 60 - exit 1 - fi - - # inspired by poky/meta/recipes-core/initrdscripts/files/install-efi.sh - target_device_list="" - current_root_dev_type=$(findmnt / -o fstype -n) - exclude_list=() - - if [ "$current_root_dev_type" = "nfs" ]; then - current_root_dev="nfs" - exclude_list+=("nfs") - else - # For normal or immutable systems, get the backing device of '/' - root_source=$(findmnt / -o source -n) - root_source_resolved=$(readlink -f "$root_source" 2>/dev/null || echo "$root_source") - current_root_dev=${root_source_resolved#/dev/} - - # Always exclude the exact device mounted as / - exclude_list+=("$current_root_dev") - - if [[ "$current_root_dev" =~ ^(mmcblk|nvme) ]]; then - base_no_part="${current_root_dev%p[0-9]*}" - else - base_no_part="${current_root_dev%%[0-9]*}" - fi - if [ -n "$base_no_part" ]; then - exclude_list+=("$base_no_part") - fi - - # If root is coming through a dm-* device (e.g., dm-verity), - # the actual physical devices appear under /sys/block//slaves/. - # We must exclude those slaves as well, otherwise the installer - # might show the live USB stick as a valid target. - if [ -d "/sys/block/$current_root_dev/slaves" ]; then - for slave in /sys/block/"$current_root_dev"/slaves/*; do - [ -e "$slave" ] || continue - slave_dev=$(basename "$slave") - exclude_list+=("$slave_dev") - slave_base=${slave_dev%%[0-9]*} - [ -n "$slave_base" ] && exclude_list+=("$slave_base") - done - fi - fi - - echo "Searching for target device..." - - devices=$(find /sys/block/ -type b,c,f,l -not -iname "mmcblk*" -printf "%f\n") || true - mmc_devices=$(find /sys/block/ -type b,c,f,l -iname "mmcblk[0-9]" -printf "%f\n") || true - devices="$devices $mmc_devices" - - for device in $devices; do - is_raid_member=0 - - if [ -d "/sys/block/$device/holders" ] && [ ! -d "/sys/block/$device/md" ]; then - for holder_path in /sys/block/$device/holders/*; do - holder_name=$(basename "$holder_path") - case "$holder_name" in - md[0-9]*) - is_raid_member=1 - break - ;; - esac - done - fi - - if [ "$is_raid_member" -eq 1 ]; then - continue # Skip RAID member disks - fi - - if [[ "$device" == md* ]]; then - if [ -f "/sys/block/$device/md/array_state" ]; then - state=$(cat /sys/block/$device/md/array_state) - if [ "$state" != "active" ] && [ "$state" != "clean" ]; then - continue - fi - else - continue - fi - fi - - case $device in - dm-*) - # skip device-mapper device - ;; - loop*) - # skip loop device - ;; - mtd*) - ;; - sr*) - # skip CDROM device - ;; - ram*) - # skip ram device - ;; - zram*) - # skip zram device - ;; - *) - #skip any excluded devices (root and its slaves) - skip_device=0 - for ex in "${exclude_list[@]}"; do - if [[ "$device" == "$ex"* ]]; then - skip_device=1 - break - fi - done - - if [ "$skip_device" -eq 0 ]; then - target_device_list="$target_device_list $device" - fi - ;; - esac - done - - if [ -z "${target_device_list}" ]; then - dialog --msgbox "You need another device (besides the live device /dev/${current_root_dev}) to install the image. Installation aborted." 7 60 - exit 1 - fi - - if [ "$(echo "$target_device_list" | wc -w)" -gt 1 ]; then - array=() - for target in $(echo "$target_device_list" | xargs -n1 | sort); do - target_size=$(lsblk --nodeps --noheadings -o SIZE /dev/"$target" | tr -d " ") - if cmp /dev/zero /dev/"$target" -n 1M; then - state="empty" - else - state="contains data" - fi - array+=("/dev/$target" "/dev/$target ($target_size, $state)") - done - if ! installer_target_dev=$(dialog --no-tags \ - --menu "Select device to install image to" 10 60 3 \ - "${array[@]}" --output-fd 1); then - exit 0 - fi - else - installer_target_dev="/dev/$(echo "$target_device_list" | tr -d " ")" - fi - TARGET_DEVICE_SIZE=$(lsblk --nodeps --noheadings -o SIZE "$installer_target_dev" | tr -d " ") - if ! dialog --yes-label Ok --no-label Cancel \ - --yesno "Start installing\n'$installer_image_uri'\nto $installer_target_dev (capacity: $TARGET_DEVICE_SIZE)" 7 60; then - exit 0 - fi - - # set absolute paths to be compatible with unattended mode - installer_image_uri="$installdata/$installer_image_uri" -fi - -if ! cmp /dev/zero "$installer_target_dev" -n 1M; then - if ! $installer_unattended; then - if ! dialog --defaultno \ - --yesno "WARNING: Target device is not empty! Continue anyway?" 5 60; then - exit 0 - fi - else - if [ "$installer_target_overwrite" != "OVERWRITE" ]; then - echo "Target device is not empty! -> Abort" - echo "If you want to override existing data set \"installer.target.overwrite=OVERWRITE\" on your kernel cmdline or edit your \"auto.install\" file accordingly." - - exit 1 - fi - fi -fi - -bmap_options="" - -# bmap file is expected to be next to the installer image -DISK_BMAP="${installer_image_uri%.wic*}.wic.bmap" - -if [ ! -f "$DISK_BMAP" ]; then - bmap_options="--nobmap" -fi - -if ! $installer_unattended; then - clear -fi - -# Function to compare version numbers -version_ge() { - if [ "$(printf '%s\n' "$1"X "$2" | sort -V | head -n 1)" != "$1"X ]; then - return 0 - else - return 1 - fi +#-------------------------------------------------------------------------- +# flow_run_attended +# +# Handles all attended-mode interactions and assigns: +# installer_image_uri +# installer_target_dev +# +# Returns: +# 0 on success +# 1 on hard error +# 2 on user cancel +#-------------------------------------------------------------------------- +flow_run_attended() { + local default_image + local selected_image + local selected_target + local target_device_size + + default_image=$(sys_first_default_image_name "$installdata") + if [ -n "$default_image" ] && [ -f "$installdata/$default_image" ]; then + installer_image_uri="$default_image" + fi + + if [ -z "$installer_image_uri" ] || [ ! -f "$installdata/$installer_image_uri" ]; then + selected_image=$(ui_select_image_menu "$installdata") + case $? in + 0) + installer_image_uri="$selected_image" + ;; + 1) + ui_show_error "Could not find an image to install. Installation aborted." + return 1 + ;; + 2) + return 2 + ;; + *) + return 1 + ;; + esac + fi + + if [ ! -f "$installdata/$installer_image_uri" ]; then + ui_show_error "Could not find an image to install. Installation aborted." + return 1 + fi + + echo "Searching for target device..." + sys_discover_target_devices + if [ "${#SYS_TARGET_DEVICES[@]}" -eq 0 ]; then + ui_show_error "You need another device (besides the live device /dev/${SYS_CURRENT_ROOT_DEV}) to install the image. Installation aborted." + return 1 + fi + + if [ "${#SYS_TARGET_DEVICES[@]}" -gt 1 ]; then + selected_target=$(ui_select_target_device_menu "${SYS_TARGET_DEVICES[@]}") + case $? in + 0) + installer_target_dev="$selected_target" + ;; + 1) + ui_show_error "No installable target devices available. Installation aborted." + return 1 + ;; + 2) + return 2 + ;; + *) + return 1 + ;; + esac + else + installer_target_dev="${SYS_TARGET_DEVICES[0]}" + fi + + target_device_size=$(sys_device_size "$installer_target_dev") + if ! ui_confirm_install "$installer_image_uri" "$installer_target_dev" "$target_device_size"; then + return 2 + fi + + installer_image_uri="$installdata/$installer_image_uri" + return 0 } -lockfile="/run/installer.lock" -progress_pipe="/run/installer.fifo" - -exec 9>"$lockfile" -if flock -n 9; then - # Get bmap-tools version - bmap_version=$(bmaptool --version | awk '{ print $NF }') - - if version_ge "$bmap_version" "3.6"; then - if ! mkfifo "$progress_pipe"; then - echo "Error: Failed to create named pipe $progress_pipe" - exit 1 - fi - - # Add psplash pipe to bmap_options - bmap_options="$bmap_options --psplash-pipe=$progress_pipe" - quiet_flag="-q" - - # Initialize the dialog gauge and update it dynamically - ( - while true; do - if read -r line < "$progress_pipe"; then - percentage=$(echo "$line" | awk '{ print $2 }') - echo "$percentage" - fi - done - ) | dialog --gauge "Flashing image, please wait..." 10 70 0 & - - gauge_pid=$! - fi - - if ! bmaptool $quiet_flag copy $bmap_options "$installer_image_uri" "$installer_target_dev"; then - kill "$gauge_pid" - exit 1 - fi - - # Attempt to terminate the gauge process if still running. - # Errors are ignored since the process may already have exited. - kill "$gauge_pid" 2>/dev/null -else - echo "Installation already running in another console." +#-------------------------------------------------------------------------- +# flow_validate_target_overwrite_policy +# +# Enforces overwrite policy for non-empty targets in both attended and +# unattended modes. +# +# Returns: +# 0 when policy permits installation +# 1 when policy rejects installation +# 2 when user cancels in attended mode +#-------------------------------------------------------------------------- +flow_validate_target_overwrite_policy() { + if sys_device_is_empty "$installer_target_dev"; then + return 0 + fi + + if ! $installer_unattended; then + if ! ui_confirm_overwrite; then + return 2 + fi + else + if [ "$installer_target_overwrite" != "OVERWRITE" ]; then + echo "Target device is not empty! -> Abort" + echo "If you want to override existing data set \"installer.target.overwrite=OVERWRITE\" on your kernel cmdline or edit your \"auto.install\" file accordingly." + return 1 + fi + fi + + return 0 +} - # Wait for running console to create the progress pipe - sleep 5 +#-------------------------------------------------------------------------- +# flow_maybe_switch_to_attended +# +# If unattended abort-by-key is enabled, this function offers a timeout +# window to switch to attended mode. +#-------------------------------------------------------------------------- +flow_maybe_switch_to_attended() { + local abort_file + + if [ "$installer_unattended" = true ] && [ "$installer_unattended_abort_enable" = true ]; then + abort_file=/tmp/attended_mode_trigger + if ui_countdown_allow_attended_switch "$installer_unattended_abort_timeout" "$abort_file"; then + installer_unattended=false + fi + fi +} - # Check if progress pipe exists and has content - if [ -e "$progress_pipe" ]; then - echo "Installation progress..." - tail -f "$progress_pipe" | while read line; do - printf "\r%s%%" "$line" - done - else - # Periodically check if bmaptool is still running every 5 seconds - echo "Waiting for installation to finish..." - while pgrep -x "bmaptool" > /dev/null; do - sleep 5 - done - fi -fi +#-------------------------------------------------------------------------- +# flow_run +# +# Main installer flow combining attended/unattended execution paths. +#-------------------------------------------------------------------------- +flow_run() { + flow_maybe_switch_to_attended + + if ! $installer_unattended; then + flow_run_attended + case $? in + 0) + ;; + 2) + return 0 + ;; + *) + return 1 + ;; + esac + fi + + flow_validate_target_overwrite_policy + case $? in + 0) + ;; + 2) + return 0 + ;; + *) + return 1 + ;; + esac + + if ! $installer_unattended; then + clear + fi + + if ! sys_install_image_with_lock "$installer_image_uri" "$installer_target_dev"; then + if ! $installer_unattended; then + ui_show_error "Installation failed." + fi + return 1 + fi + + if ! $installer_unattended; then + ui_show_info "Installation was successful. System will be rebooted. Please remove the USB stick." + else + echo "Installation was successful." + fi + + return 0 +} -if ! $installer_unattended; then - dialog --title "Reboot" \ - --msgbox "Installation was successful. System will be rebooted. Please remove the USB stick." 6 60 -else - echo "Installation was successful." -fi +# Entrypoint: run the installer flow and propagate status. +flow_run +exit $? -exit 0