From 6b8979039062a22adfab627c378456d822e18b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuomas=20R=C3=A4s=C3=A4nen?= Date: Wed, 28 Aug 2024 18:19:00 +0300 Subject: [PATCH 1/9] puavo-reset-windows: [refactor] move usage to the top Usage and comments are merged, all win. --- parts/ltsp/puavo-install/puavo-reset-windows | 29 ++++++++------------ 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index b4757386d6..04167ab673 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -1,16 +1,20 @@ #!/bin/bash -## puavo-reset-windows -## -## Scans all block devices for Windows partitions and resets them. By -## default, asks user for a confirmation to reset. -## -## --force no questions asked -## - set -eu set -o pipefail +usage() { + cat < Date: Wed, 28 Aug 2024 18:38:01 +0300 Subject: [PATCH 2/9] puavo-reset-windows: [refactor] rename win_primary_partition => win_c_partition Because that's what it actually is. Primary is just a partition type, it does not define it's semantics. Microsoft itself calls this partition Local Disk (C:) Partition[1]. 1: https://learn.microsoft.com/en-us/windows-server/storage/disk-management/overview-of-disk-management --- parts/ltsp/puavo-install/puavo-reset-windows | 98 ++++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index 04167ab673..3747daafeb 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -68,7 +68,7 @@ logerr() { logmsg error "$1" } -print0_win_primary_partition_devpaths() +print0_win_c_partition_devpaths() { while IFS= read -r -d $'\0' ntfs_partition_devpath; do has_dirty_flag=false @@ -85,7 +85,7 @@ print0_win_primary_partition_devpaths() loginfo "Clearing the dirty flag of NTFS volume in '${ntfs_partition_devpath}'..." ntfsfix -d "${ntfs_partition_devpath}" >&2 || { logerr "Failed clear the dirty flag of NTFS volume in '${ntfs_partition_devpath}'." - continue # To the next possible windows primary partition + continue # To the next possible Windows C partition } was_dirty_flag_cleared=true fi @@ -143,20 +143,20 @@ save_cached_param() get_win_language_from_partition() { - local win_language_id win_language win_primary_partition_devpath + local win_language_id win_language win_c_partition_devpath - win_primary_partition_devpath=$1 + win_c_partition_devpath=$1 shift - ntfscat "${win_primary_partition_devpath}" 'Windows/System32/config/SYSTEM' >system_hive || { - logerr "Failed to get SYSTEM hive from '${win_primary_partition_devpath}'." + ntfscat "${win_c_partition_devpath}" 'Windows/System32/config/SYSTEM' >system_hive || { + logerr "Failed to get SYSTEM hive from '${win_c_partition_devpath}'." return 1 } win_language_id=$(hivexget system_hive 'ControlSet001\Control\Nls\Language' \ | sed -r -n 's/"InstallLanguage"="([0-9A-Fa-f]{4})"$/\1/p' \ | tr '[:upper:]' '[:lower:]') || { - logerr "Failed to parse InstallLanguage from SYSTEM hive of '${win_primary_partition_devpath}'." + logerr "Failed to parse InstallLanguage from SYSTEM hive of '${win_c_partition_devpath}'." return 1 } @@ -196,10 +196,10 @@ get_win_language_from_partition() get_win_language() { - local win_primary_partition_devpath - win_primary_partition_devpath=$1 + local win_c_partition_devpath + win_c_partition_devpath=$1 - if ! get_win_language_from_partition "$win_primary_partition_devpath"; then + if ! get_win_language_from_partition "$win_c_partition_devpath"; then load_cached_param language || return 1 loginfo 'Loaded Windows language from reset cache' fi @@ -210,19 +210,19 @@ get_win_language() get_win_product_name_from_partition() { local win_build_number \ - win_primary_partition_devpath \ + win_c_partition_devpath \ win_product_name - win_primary_partition_devpath=$1 + win_c_partition_devpath=$1 shift - ntfscat "${win_primary_partition_devpath}" 'Windows/System32/config/SOFTWARE' >software_hive || { - logerr "Failed to get SOFTWARE hive from '${win_primary_partition_devpath}'." + ntfscat "${win_c_partition_devpath}" 'Windows/System32/config/SOFTWARE' >software_hive || { + logerr "Failed to get SOFTWARE hive from '${win_c_partition_devpath}'." return 1 } win_product_name=$(hivexget software_hive 'Microsoft\Windows NT\CurrentVersion' | sed -r -n 's/"ProductName"="(.+)"$/\1/p') || { - logerr "Failed to parse ProductName from SOFTWARE hive of '${win_primary_partition_devpath}'." + logerr "Failed to parse ProductName from SOFTWARE hive of '${win_c_partition_devpath}'." return 1 } @@ -230,13 +230,13 @@ get_win_product_name_from_partition() 'Windows 10 Home' | 'Windows 10 Pro' | 'Windows 11 Home' | 'Windows 11 Pro') ;; *) - logerr "Ignoring unsupported '${win_product_name}' on '${win_primary_partition_devpath}'." + logerr "Ignoring unsupported '${win_product_name}' on '${win_c_partition_devpath}'." return 1 ;; esac win_build_number=$(hivexget software_hive 'Microsoft\Windows NT\CurrentVersion' | sed -r -n 's/"CurrentBuildNumber"="(.+)"$/\1/p') || { - logerr "Failed to parse CurrentBuildNumber from SOFTWARE hive of '${win_primary_partition_devpath}'." + logerr "Failed to parse CurrentBuildNumber from SOFTWARE hive of '${win_c_partition_devpath}'." return 1 } @@ -261,10 +261,10 @@ get_win_product_name_from_partition() get_win_product_name() { - local win_primary_partition_devpath - win_primary_partition_devpath=$1 + local win_c_partition_devpath + win_c_partition_devpath=$1 - if ! get_win_product_name_from_partition "$win_primary_partition_devpath"; then + if ! get_win_product_name_from_partition "$win_c_partition_devpath"; then load_cached_param product_name || return 1 loginfo 'Loaded Windows product name from reset cache' fi @@ -538,7 +538,7 @@ choose_wim_image_to_use() reset_win() { local wim_image_baseurl wim_image_name win_language \ - win_primary_partition_devpath win_product_name + win_c_partition_devpath win_product_name win_product_name=$1 shift @@ -546,7 +546,7 @@ reset_win() win_language=$1 shift - win_primary_partition_devpath=$1 + win_c_partition_devpath=$1 shift wim_image_baseurl=$(get_wim_catalogue) || return 1 @@ -554,7 +554,7 @@ reset_win() wim_image_name=$(choose_wim_image_to_use "$win_language" \ "$win_product_name") - loginfo "Reseting '${win_product_name} (${win_language})' on '${win_primary_partition_devpath}'..." + loginfo "Reseting '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'..." fetch_wim_image "$wim_image_baseurl" "$wim_image_name" || { logerr "Failed to fetch WIM file for '${win_product_name} (${win_language})'." @@ -563,29 +563,29 @@ reset_win() wim_image_index=$(print0_wim_image_index "$wim_image_name" "$win_product_name") - loginfo "Securely erasing Windows on '${win_primary_partition_devpath}'" - blkdiscard "${win_primary_partition_devpath}" || { - logerr "Failed to run blkdiscard to '${win_primary_partition_devpath}'" + loginfo "Securely erasing Windows on '${win_c_partition_devpath}'" + blkdiscard "${win_c_partition_devpath}" || { + logerr "Failed to run blkdiscard to '${win_c_partition_devpath}'" return 1 } loginfo "Secure erase done." - loginfo "Re-creating NTFS filesystem on '${win_primary_partition_devpath}'..." + loginfo "Re-creating NTFS filesystem on '${win_c_partition_devpath}'..." # Force needed to overwrite the existing filesystem without questions. - mkfs.ntfs -f "${win_primary_partition_devpath}" || { - logerr "Failed to create NTFS filesystem on '${win_primary_partition_devpath}'" + mkfs.ntfs -f "${win_c_partition_devpath}" || { + logerr "Failed to create NTFS filesystem on '${win_c_partition_devpath}'" return 1 } - loginfo "Re-created NTFS filesystem on '${win_primary_partition_devpath}'." + loginfo "Re-created NTFS filesystem on '${win_c_partition_devpath}'." - loginfo "Applying WIM image to '${win_primary_partition_devpath}'..." - wimapply "${wim_image_name}" "${wim_image_index}" "${win_primary_partition_devpath}" || { - logerr "Failed to apply WIM image '${wim_image_index}' from '${wim_image_name}' to '${win_primary_partition_devpath}'." + loginfo "Applying WIM image to '${win_c_partition_devpath}'..." + wimapply "${wim_image_name}" "${wim_image_index}" "${win_c_partition_devpath}" || { + logerr "Failed to apply WIM image '${wim_image_index}' from '${wim_image_name}' to '${win_c_partition_devpath}'." return 1 } - loginfo "Applied WIM image to '${win_primary_partition_devpath}'." + loginfo "Applied WIM image to '${win_c_partition_devpath}'." - loginfo "Reset '${win_product_name} (${win_language})' on '${win_primary_partition_devpath}' to factory settings successfully." + loginfo "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' to factory settings successfully." return 0 } @@ -617,19 +617,19 @@ get_win_language_from_puavo_conf() reset_all_wins() { - local returnval win_language win_product_name + local returnval win_c_partition_devpath win_language win_product_name returnval=0 - while IFS= read -r -d $'\0' win_primary_partition_devpath; do - win_product_name=$(get_win_product_name "${win_primary_partition_devpath}") || { - logerr "Failed to get the product name of Windows on '${win_primary_partition_devpath}'." + while IFS= read -r -d $'\0' win_c_partition_devpath; do + win_product_name=$(get_win_product_name "${win_c_partition_devpath}") || { + logerr "Failed to get the product name of Windows on '${win_c_partition_devpath}'." win_product_name='Windows 11 Pro' logwarning "Using '${win_product_name}' as a fallback." } - win_language=$(get_win_language "${win_primary_partition_devpath}") || { - logerr "Failed to get the language tag of Windows on '${win_primary_partition_devpath}'." + win_language=$(get_win_language "${win_c_partition_devpath}") || { + logerr "Failed to get the language tag of Windows on '${win_c_partition_devpath}'." win_language="$(get_win_language_from_puavo_conf)" || { logerr 'Failed to get fallback Windows language from Puavo configuration, which should never happen!' win_language='English' @@ -637,27 +637,27 @@ reset_all_wins() logwarning "Using '${win_language}' as a fallback." } - loginfo "Detected '${win_product_name} (${win_language})' on '${win_primary_partition_devpath}'." + loginfo "Detected '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ - "Reset '${win_product_name} (${win_language})' on '${win_primary_partition_devpath}'?" 5 100 || { - loginfo "Skipping '${win_product_name} (${win_language})' on '${win_primary_partition_devpath}'." + "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'?" 5 100 || { + loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." continue } $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ - "All data will be lost on '${win_primary_partition_devpath}'! Are you really sure you want to proceed?" 5 100 || { - loginfo "Skipping '${win_product_name} (${win_language})' on '${win_primary_partition_devpath}'." + "All data will be lost on '${win_c_partition_devpath}'! Are you really sure you want to proceed?" 5 100 || { + loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." continue } - reset_win "${win_product_name}" "${win_language}" "${win_primary_partition_devpath}" || { - logerr "Failed to reset '${win_product_name} (${win_language})' on '${win_primary_partition_devpath}'." + reset_win "${win_product_name}" "${win_language}" "${win_c_partition_devpath}" || { + logerr "Failed to reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." returnval=1 continue } - done < <(print0_win_primary_partition_devpaths) || { + done < <(print0_win_c_partition_devpaths) || { logerr "Unexpected termination of Windows reset loop" returnval=1 } From 3afe9f1867e81651e56d5b45bf6aa1ab17955e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuomas=20R=C3=A4s=C3=A4nen?= Date: Wed, 28 Aug 2024 18:48:46 +0300 Subject: [PATCH 3/9] puavo-reset-windows: [refactor] rename reset_win() => install_win() Because the function installs new Windows on a given partition from WIM image. Reseting is the main process, installation is a sub-process. --- parts/ltsp/puavo-install/puavo-reset-windows | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index 3747daafeb..8f17031233 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -535,7 +535,7 @@ choose_wim_image_to_use() printf "%s\n" "$preferred_versions" } -reset_win() +install_win() { local wim_image_baseurl wim_image_name win_language \ win_c_partition_devpath win_product_name @@ -554,7 +554,7 @@ reset_win() wim_image_name=$(choose_wim_image_to_use "$win_language" \ "$win_product_name") - loginfo "Reseting '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'..." + loginfo "Installing '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'..." fetch_wim_image "$wim_image_baseurl" "$wim_image_name" || { logerr "Failed to fetch WIM file for '${win_product_name} (${win_language})'." @@ -563,20 +563,20 @@ reset_win() wim_image_index=$(print0_wim_image_index "$wim_image_name" "$win_product_name") - loginfo "Securely erasing Windows on '${win_c_partition_devpath}'" + loginfo "Securely erasing '${win_c_partition_devpath}'" blkdiscard "${win_c_partition_devpath}" || { logerr "Failed to run blkdiscard to '${win_c_partition_devpath}'" return 1 } loginfo "Secure erase done." - loginfo "Re-creating NTFS filesystem on '${win_c_partition_devpath}'..." + loginfo "Creating NTFS filesystem on '${win_c_partition_devpath}'..." # Force needed to overwrite the existing filesystem without questions. mkfs.ntfs -f "${win_c_partition_devpath}" || { logerr "Failed to create NTFS filesystem on '${win_c_partition_devpath}'" return 1 } - loginfo "Re-created NTFS filesystem on '${win_c_partition_devpath}'." + loginfo "Created NTFS filesystem on '${win_c_partition_devpath}'." loginfo "Applying WIM image to '${win_c_partition_devpath}'..." wimapply "${wim_image_name}" "${wim_image_index}" "${win_c_partition_devpath}" || { @@ -585,7 +585,7 @@ reset_win() } loginfo "Applied WIM image to '${win_c_partition_devpath}'." - loginfo "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' to factory settings successfully." + loginfo "Installed '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' to factory settings successfully." return 0 } @@ -651,12 +651,14 @@ reset_all_wins() continue } - reset_win "${win_product_name}" "${win_language}" "${win_c_partition_devpath}" || { - logerr "Failed to reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + install_win "${win_product_name}" "${win_language}" "${win_c_partition_devpath}" || { + logerr "Failed to install '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." returnval=1 continue } + loginfo "Windows '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' reset to factory defaults." + done < <(print0_win_c_partition_devpaths) || { logerr "Unexpected termination of Windows reset loop" returnval=1 From dc63dc3cd207dd1a98337856dadb75727e49054e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuomas=20R=C3=A4s=C3=A4nen?= Date: Wed, 28 Aug 2024 19:02:06 +0300 Subject: [PATCH 4/9] puavo-reset-windows: [refactor] split reset_all_wins() to reset_win() and reset_all_wins() --- parts/ltsp/puavo-install/puavo-reset-windows | 78 +++++++++++--------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index 8f17031233..b7e7c91270 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -615,50 +615,62 @@ get_win_language_from_puavo_conf() printf '%s' "${win_language}" } -reset_all_wins() +reset_win() { - local returnval win_c_partition_devpath win_language win_product_name + local win_c_partition_devpath win_language win_product_name - returnval=0 + win_c_partition_devpath=$1 + shift - while IFS= read -r -d $'\0' win_c_partition_devpath; do - win_product_name=$(get_win_product_name "${win_c_partition_devpath}") || { - logerr "Failed to get the product name of Windows on '${win_c_partition_devpath}'." - win_product_name='Windows 11 Pro' - logwarning "Using '${win_product_name}' as a fallback." - } + win_product_name=$(get_win_product_name "${win_c_partition_devpath}") || { + logerr "Failed to get the product name of Windows on '${win_c_partition_devpath}'." + win_product_name='Windows 11 Pro' + logwarning "Using '${win_product_name}' as a fallback." + } - win_language=$(get_win_language "${win_c_partition_devpath}") || { - logerr "Failed to get the language tag of Windows on '${win_c_partition_devpath}'." - win_language="$(get_win_language_from_puavo_conf)" || { - logerr 'Failed to get fallback Windows language from Puavo configuration, which should never happen!' - win_language='English' - } - logwarning "Using '${win_language}' as a fallback." + win_language=$(get_win_language "${win_c_partition_devpath}") || { + logerr "Failed to get the language tag of Windows on '${win_c_partition_devpath}'." + win_language="$(get_win_language_from_puavo_conf)" || { + logerr 'Failed to get fallback Windows language from Puavo configuration, which should never happen!' + win_language='English' } + logwarning "Using '${win_language}' as a fallback." + } - loginfo "Detected '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + loginfo "Detected '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ - "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'?" 5 100 || { - loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - continue - } + $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ + "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'?" 5 100 || { + loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + return 0 + } - $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ - "All data will be lost on '${win_c_partition_devpath}'! Are you really sure you want to proceed?" 5 100 || { - loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - continue - } + $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ + "All data will be lost on '${win_c_partition_devpath}'! Are you really sure you want to proceed?" 5 100 || { + loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + return 0 + } - install_win "${win_product_name}" "${win_language}" "${win_c_partition_devpath}" || { - logerr "Failed to install '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - returnval=1 - continue - } + install_win "${win_product_name}" "${win_language}" "${win_c_partition_devpath}" || { + logerr "Failed to install '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + return 1 + } + + loginfo "Windows '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' reset to factory defaults." - loginfo "Windows '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' reset to factory defaults." + return 0 +} +reset_all_wins() +{ + local returnval win_c_partition_devpath + + returnval=0 + + while IFS= read -r -d $'\0' win_c_partition_devpath; do + reset_win "${win_c_partition_devpath}" || { + returnval=1 + } done < <(print0_win_c_partition_devpaths) || { logerr "Unexpected termination of Windows reset loop" returnval=1 From cecf7fe67c48da8a632b1959dcc9ae480bf8df0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuomas=20R=C3=A4s=C3=A4nen?= Date: Fri, 30 Aug 2024 21:29:23 +0300 Subject: [PATCH 5/9] puavo-reset-windows: [refactor] prefix global variables with g_ --- parts/ltsp/puavo-install/puavo-reset-windows | 70 ++++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index b7e7c91270..a0171ce774 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -16,37 +16,37 @@ EOF } ## Globals -exitval=1 # Premature exit is an error by default. -use_force=false # --force sets to true -lockfd= # Will be set when lockfile is opened -RESET_STATE_DIR=/state/windows -WORK_DIR=/home/.puavo-reset-windows # Where WIM files will be downloaded, mounted etc. -WIM_CATALOGUE_PATH="${WORK_DIR}/wim.json" -PID_FILE=/run/puavo-reset-windows.pid # Locks this file to ensure only one puavo-reset-windows is running +g_exitval=1 # Premature exit is an error by default. +g_use_force=false # --force sets to true +g_lockfd= # Will be set when lockfile is opened +G_RESET_STATE_DIR=/state/windows +G_WORK_DIR=/home/.puavo-reset-windows # Where WIM files will be downloaded, mounted etc. +G_WIM_CATALOGUE_PATH="${G_WORK_DIR}/wim.json" +G_PID_FILE=/run/puavo-reset-windows.pid # Locks this file to ensure only one puavo-reset-windows is running on_exit() { set +e loginfo 'Unmounting WIM files...' - find "${WORK_DIR}" -type d -name '*.mountpoint' -exec umount -q {} \; + find "${G_WORK_DIR}" -type d -name '*.mountpoint' -exec umount -q {} \; loginfo 'Unmounted WIM files.' - loginfo "Removing working directory '${WORK_DIR}'..." - rm -rf "${WORK_DIR}" - loginfo "Removed working directory '${WORK_DIR}'." + loginfo "Removing working directory '${G_WORK_DIR}'..." + rm -rf "${G_WORK_DIR}" + loginfo "Removed working directory '${G_WORK_DIR}'." - loginfo "Removing PID file '${PID_FILE}'..." - rm -f "${PID_FILE}" - loginfo "Removed PID file '${PID_FILE}'." + loginfo "Removing PID file '${G_PID_FILE}'..." + rm -f "${G_PID_FILE}" + loginfo "Removed PID file '${G_PID_FILE}'." - if [ $exitval -ne 0 ]; then + if [ $g_exitval -ne 0 ]; then logerr 'Failed!' else loginfo 'Succeeded.' fi - exit $exitval + exit $g_exitval } logmsg() { @@ -81,7 +81,7 @@ print0_win_c_partition_devpaths() fi set -o pipefail - if $use_force && $has_dirty_flag; then + if $g_use_force && $has_dirty_flag; then loginfo "Clearing the dirty flag of NTFS volume in '${ntfs_partition_devpath}'..." ntfsfix -d "${ntfs_partition_devpath}" >&2 || { logerr "Failed clear the dirty flag of NTFS volume in '${ntfs_partition_devpath}'." @@ -123,7 +123,7 @@ load_cached_param() local key value key=$1 - if ! value=$(cat "${RESET_STATE_DIR}/${key}" 2>/dev/null); then + if ! value=$(cat "${G_RESET_STATE_DIR}/${key}" 2>/dev/null); then logerr "Could not load '${key}' parameter from cache" return 1 fi @@ -136,9 +136,9 @@ save_cached_param() local key value key=$1 value=$2 - mkdir -p "$RESET_STATE_DIR" || return 1 - printf "%s\n" "$value" > "${RESET_STATE_DIR}/${key}.tmp" || return 1 - mv "${RESET_STATE_DIR}/${key}.tmp" "${RESET_STATE_DIR}/${key}" || return 1 + mkdir -p "$G_RESET_STATE_DIR" || return 1 + printf "%s\n" "$value" > "${G_RESET_STATE_DIR}/${key}.tmp" || return 1 + mv "${G_RESET_STATE_DIR}/${key}.tmp" "${G_RESET_STATE_DIR}/${key}" || return 1 } get_win_language_from_partition() @@ -312,7 +312,7 @@ verify_wim_image() loginfo "Verifying WIM file '${wim_image_name}'..." jq -r --arg wim_image "$wim_image_name" ' .images[$wim_image].sha512sum + " " + $wim_image - ' "$WIM_CATALOGUE_PATH" \ + ' "$G_WIM_CATALOGUE_PATH" \ | sha512sum --strict --status -c || { logerr "Failed to verify WIM file '${wim_image_name}'." return 1 @@ -467,8 +467,8 @@ get_wim_catalogue() wim_image_source_urls=$(puavo-conf puavo.windows.image.sources) - wim_gpg_tmppath="${WIM_CATALOGUE_PATH}.gpg.tmp" - wim_tmppath="${WIM_CATALOGUE_PATH}.tmp" + wim_gpg_tmppath="${G_WIM_CATALOGUE_PATH}.gpg.tmp" + wim_tmppath="${G_WIM_CATALOGUE_PATH}.tmp" for url in $wim_image_source_urls; do if ! wget_with_certauth -q \ @@ -485,7 +485,7 @@ get_wim_catalogue() continue fi - mv "$wim_tmppath" "$WIM_CATALOGUE_PATH" || return 1 + mv "$wim_tmppath" "$G_WIM_CATALOGUE_PATH" || return 1 printf "%s/images" "${url%/*}" || return 1 return 0 done @@ -639,13 +639,13 @@ reset_win() loginfo "Detected '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ + $g_use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'?" 5 100 || { loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." return 0 } - $use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ + $g_use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ "All data will be lost on '${win_c_partition_devpath}'! Are you really sure you want to proceed?" 5 100 || { loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." return 0 @@ -682,7 +682,7 @@ reset_all_wins() while [ $# -ne 0 ]; do case "$1" in --force) - use_force=true + g_use_force=true shift ;; --) @@ -702,21 +702,21 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi -exec {lockfd}<> "${PID_FILE}" -flock -x -n "${lockfd}" || { +exec {g_lockfd}<> "${G_PID_FILE}" +flock -x -n "${g_lockfd}" || { logerr "puavo-reset-windows is already running!" exit 1 } trap on_exit EXIT -echo "$$" >"${PID_FILE}" +echo "$$" >"${G_PID_FILE}" -install -d -m 0700 "${WORK_DIR}" -cd "${WORK_DIR}" -loginfo "Changed current working directory to '${WORK_DIR}'." +install -d -m 0700 "${G_WORK_DIR}" +cd "${G_WORK_DIR}" +loginfo "Changed current working directory to '${G_WORK_DIR}'." reset_all_wins # Reached the end, everything is fine then. -exitval=0 +g_exitval=0 From c87589d7f688936a10305c1d11a2186d4976b500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuomas=20R=C3=A4s=C3=A4nen?= Date: Wed, 28 Aug 2024 20:21:53 +0300 Subject: [PATCH 6/9] puavo-reset-windows: add optional command line argument, target partition --- parts/ltsp/puavo-install/puavo-reset-windows | 26 +++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index a0171ce774..870f5450be 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -5,10 +5,12 @@ set -o pipefail usage() { cat < Date: Sun, 29 Sep 2024 07:35:10 +0300 Subject: [PATCH 7/9] puavo-reset-windows: [refactor] fix indentation --- parts/ltsp/puavo-install/puavo-reset-windows | 978 +++++++++---------- 1 file changed, 489 insertions(+), 489 deletions(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index 870f5450be..dd153a97ec 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -29,27 +29,27 @@ G_PID_FILE=/run/puavo-reset-windows.pid # Locks this file to ensure only one pua on_exit() { - set +e + set +e - loginfo 'Unmounting WIM files...' - find "${G_WORK_DIR}" -type d -name '*.mountpoint' -exec umount -q {} \; - loginfo 'Unmounted WIM files.' + loginfo 'Unmounting WIM files...' + find "${G_WORK_DIR}" -type d -name '*.mountpoint' -exec umount -q {} \; + loginfo 'Unmounted WIM files.' - loginfo "Removing working directory '${G_WORK_DIR}'..." - rm -rf "${G_WORK_DIR}" - loginfo "Removed working directory '${G_WORK_DIR}'." + loginfo "Removing working directory '${G_WORK_DIR}'..." + rm -rf "${G_WORK_DIR}" + loginfo "Removed working directory '${G_WORK_DIR}'." - loginfo "Removing PID file '${G_PID_FILE}'..." - rm -f "${G_PID_FILE}" - loginfo "Removed PID file '${G_PID_FILE}'." + loginfo "Removing PID file '${G_PID_FILE}'..." + rm -f "${G_PID_FILE}" + loginfo "Removed PID file '${G_PID_FILE}'." - if [ $g_exitval -ne 0 ]; then - logerr 'Failed!' - else - loginfo 'Succeeded.' - fi + if [ $g_exitval -ne 0 ]; then + logerr 'Failed!' + else + loginfo 'Succeeded.' + fi - exit $g_exitval + exit $g_exitval } logmsg() { @@ -73,48 +73,48 @@ logerr() { print0_win_c_partition_devpaths() { - while IFS= read -r -d $'\0' ntfs_partition_devpath; do - has_dirty_flag=false - was_dirty_flag_cleared=false - - set +o pipefail # ntfsls is expected to fail, we are interested in its error output - if ntfsls -F "${ntfs_partition_devpath}" 2>&1 >/dev/null | head -n1 | grep -q -x 'Volume is scheduled for check.'; then - loginfo "NTFS volume in '${ntfs_partition_devpath}' is dirty." - has_dirty_flag=true - fi - set -o pipefail - - if $g_use_force && $has_dirty_flag; then - loginfo "Clearing the dirty flag of NTFS volume in '${ntfs_partition_devpath}'..." - ntfsfix -d "${ntfs_partition_devpath}" >&2 || { - logerr "Failed clear the dirty flag of NTFS volume in '${ntfs_partition_devpath}'." - continue # To the next possible Windows C partition - } - was_dirty_flag_cleared=true - fi - - ntfsls -F "${ntfs_partition_devpath}" | grep -q -x 'Windows/' || { - if $was_dirty_flag_cleared; then - loginfo "Restoring the dirty flag of NTFS volume in '${ntfs_partition_devpath}'..." - ntfsfix "${ntfs_partition_devpath}" >&2 || { - # Well, this really should not be possible in - # practice. We have already succesfully cleared - # the dirty bit just a moment ago, so surely - # setting it back should work too, unless ntfsfix - # is broken or something catastrophic has happened - # in the filesystem or on the device. - logerr "Failed to set the dirty flag of NTFS volume in '${ntfs_partition_devpath}'." - } - fi - continue + while IFS= read -r -d $'\0' ntfs_partition_devpath; do + has_dirty_flag=false + was_dirty_flag_cleared=false + + set +o pipefail # ntfsls is expected to fail, we are interested in its error output + if ntfsls -F "${ntfs_partition_devpath}" 2>&1 >/dev/null | head -n1 | grep -q -x 'Volume is scheduled for check.'; then + loginfo "NTFS volume in '${ntfs_partition_devpath}' is dirty." + has_dirty_flag=true + fi + set -o pipefail + + if $g_use_force && $has_dirty_flag; then + loginfo "Clearing the dirty flag of NTFS volume in '${ntfs_partition_devpath}'..." + ntfsfix -d "${ntfs_partition_devpath}" >&2 || { + logerr "Failed clear the dirty flag of NTFS volume in '${ntfs_partition_devpath}'." + continue # To the next possible Windows C partition + } + was_dirty_flag_cleared=true + fi + + ntfsls -F "${ntfs_partition_devpath}" | grep -q -x 'Windows/' || { + if $was_dirty_flag_cleared; then + loginfo "Restoring the dirty flag of NTFS volume in '${ntfs_partition_devpath}'..." + ntfsfix "${ntfs_partition_devpath}" >&2 || { + # Well, this really should not be possible in + # practice. We have already succesfully cleared + # the dirty bit just a moment ago, so surely + # setting it back should work too, unless ntfsfix + # is broken or something catastrophic has happened + # in the filesystem or on the device. + logerr "Failed to set the dirty flag of NTFS volume in '${ntfs_partition_devpath}'." } - printf '%s\0' "${ntfs_partition_devpath}" - # GPT Microsoft basic data partition GUID: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 - # MBR HPFS/NTFS/exFAT type: 0x7 - done < <(lsblk -n -l -o PATH,PARTTYPE | awk '$2 == "0x7" || $2 == "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" {printf "%s\0", $1}') || { - logerr 'Failed to list partitions.' - return 1 + fi + continue } + printf '%s\0' "${ntfs_partition_devpath}" + # GPT Microsoft basic data partition GUID: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 + # MBR HPFS/NTFS/exFAT type: 0x7 + done < <(lsblk -n -l -o PATH,PARTTYPE | awk '$2 == "0x7" || $2 == "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" {printf "%s\0", $1}') || { + logerr 'Failed to list partitions.' + return 1 + } } # Use parameter cache to store the Windows installation product name and @@ -123,400 +123,400 @@ print0_win_c_partition_devpaths() # previous information and subsequent reset attempts will fail. load_cached_param() { - local key value - key=$1 + local key value + key=$1 - if ! value=$(cat "${G_RESET_STATE_DIR}/${key}" 2>/dev/null); then - logerr "Could not load '${key}' parameter from cache" - return 1 - fi + if ! value=$(cat "${G_RESET_STATE_DIR}/${key}" 2>/dev/null); then + logerr "Could not load '${key}' parameter from cache" + return 1 + fi - printf '%s' "$value" + printf '%s' "$value" } save_cached_param() { - local key value - key=$1 - value=$2 - mkdir -p "$G_RESET_STATE_DIR" || return 1 - printf "%s\n" "$value" > "${G_RESET_STATE_DIR}/${key}.tmp" || return 1 - mv "${G_RESET_STATE_DIR}/${key}.tmp" "${G_RESET_STATE_DIR}/${key}" || return 1 + local key value + key=$1 + value=$2 + mkdir -p "$G_RESET_STATE_DIR" || return 1 + printf "%s\n" "$value" > "${G_RESET_STATE_DIR}/${key}.tmp" || return 1 + mv "${G_RESET_STATE_DIR}/${key}.tmp" "${G_RESET_STATE_DIR}/${key}" || return 1 } get_win_language_from_partition() { - local win_language_id win_language win_c_partition_devpath + local win_language_id win_language win_c_partition_devpath - win_c_partition_devpath=$1 - shift + win_c_partition_devpath=$1 + shift - ntfscat "${win_c_partition_devpath}" 'Windows/System32/config/SYSTEM' >system_hive || { - logerr "Failed to get SYSTEM hive from '${win_c_partition_devpath}'." - return 1 - } + ntfscat "${win_c_partition_devpath}" 'Windows/System32/config/SYSTEM' >system_hive || { + logerr "Failed to get SYSTEM hive from '${win_c_partition_devpath}'." + return 1 + } - win_language_id=$(hivexget system_hive 'ControlSet001\Control\Nls\Language' \ - | sed -r -n 's/"InstallLanguage"="([0-9A-Fa-f]{4})"$/\1/p' \ - | tr '[:upper:]' '[:lower:]') || { - logerr "Failed to parse InstallLanguage from SYSTEM hive of '${win_c_partition_devpath}'." - return 1 - } + win_language_id=$(hivexget system_hive 'ControlSet001\Control\Nls\Language' \ + | sed -r -n 's/"InstallLanguage"="([0-9A-Fa-f]{4})"$/\1/p' \ + | tr '[:upper:]' '[:lower:]') || { + logerr "Failed to parse InstallLanguage from SYSTEM hive of '${win_c_partition_devpath}'." + return 1 + } + + ## https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf + case "${win_language_id}" in + '0407') + win_language='German' + ;; + '0409') + win_language='English' + ;; + '040b') + win_language='Finnish' + ;; + '041d') + win_language='Swedish' + ;; + '0419') + win_language='Russian' + ;; + '0422') + win_language='Ukrainian' + ;; + *) + logerr "Unsupported language ID '${win_language_id}'" + return 1 + ;; + esac - ## https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf - case "${win_language_id}" in - '0407') - win_language='German' - ;; - '0409') - win_language='English' - ;; - '040b') - win_language='Finnish' - ;; - '041d') - win_language='Swedish' - ;; - '0419') - win_language='Russian' - ;; - '0422') - win_language='Ukrainian' - ;; - *) - logerr "Unsupported language ID '${win_language_id}'" - return 1 - ;; - esac - - save_cached_param language "$win_language" || { - logerr 'Could not save Windows language name to cache' - return 1 - } + save_cached_param language "$win_language" || { + logerr 'Could not save Windows language name to cache' + return 1 + } - printf '%s' "$win_language" + printf '%s' "$win_language" } get_win_language() { - local win_c_partition_devpath - win_c_partition_devpath=$1 + local win_c_partition_devpath + win_c_partition_devpath=$1 - if ! get_win_language_from_partition "$win_c_partition_devpath"; then - load_cached_param language || return 1 - loginfo 'Loaded Windows language from reset cache' - fi + if ! get_win_language_from_partition "$win_c_partition_devpath"; then + load_cached_param language || return 1 + loginfo 'Loaded Windows language from reset cache' + fi - return 0 + return 0 } get_win_product_name_from_partition() { - local win_build_number \ - win_c_partition_devpath \ - win_product_name - - win_c_partition_devpath=$1 - shift + local win_build_number \ + win_c_partition_devpath \ + win_product_name - ntfscat "${win_c_partition_devpath}" 'Windows/System32/config/SOFTWARE' >software_hive || { - logerr "Failed to get SOFTWARE hive from '${win_c_partition_devpath}'." - return 1 - } + win_c_partition_devpath=$1 + shift - win_product_name=$(hivexget software_hive 'Microsoft\Windows NT\CurrentVersion' | sed -r -n 's/"ProductName"="(.+)"$/\1/p') || { - logerr "Failed to parse ProductName from SOFTWARE hive of '${win_c_partition_devpath}'." - return 1 - } + ntfscat "${win_c_partition_devpath}" 'Windows/System32/config/SOFTWARE' >software_hive || { + logerr "Failed to get SOFTWARE hive from '${win_c_partition_devpath}'." + return 1 + } - case "$win_product_name" in - 'Windows 10 Home' | 'Windows 10 Pro' | 'Windows 11 Home' | 'Windows 11 Pro') - ;; - *) - logerr "Ignoring unsupported '${win_product_name}' on '${win_c_partition_devpath}'." - return 1 - ;; - esac - - win_build_number=$(hivexget software_hive 'Microsoft\Windows NT\CurrentVersion' | sed -r -n 's/"CurrentBuildNumber"="(.+)"$/\1/p') || { - logerr "Failed to parse CurrentBuildNumber from SOFTWARE hive of '${win_c_partition_devpath}'." - return 1 - } + win_product_name=$(hivexget software_hive 'Microsoft\Windows NT\CurrentVersion' | sed -r -n 's/"ProductName"="(.+)"$/\1/p') || { + logerr "Failed to parse ProductName from SOFTWARE hive of '${win_c_partition_devpath}'." + return 1 + } - ## Windows 11 lies and claims to be Windows 10, but the build - ## number seems to reveal the truth. Windows 11 build numbers - ## start from 22000. - ## - ## https://learn.microsoft.com/en-us/answers/questions/555857/windows-11-product-name-in-registry - ## https://learn.microsoft.com/en-us/windows/release-health/release-information - if [ "${win_build_number}" -ge 22000 ]; then - # This is actually Windows 11. - win_product_name=$(echo -n "${win_product_name}" | sed -r 's/^Windows 10/Windows 11/') - fi + case "$win_product_name" in + 'Windows 10 Home' | 'Windows 10 Pro' | 'Windows 11 Home' | 'Windows 11 Pro') + ;; + *) + logerr "Ignoring unsupported '${win_product_name}' on '${win_c_partition_devpath}'." + return 1 + ;; + esac - save_cached_param product_name "$win_product_name" || { - logerr 'Could not save Windows product name to cache' - return 1 - } + win_build_number=$(hivexget software_hive 'Microsoft\Windows NT\CurrentVersion' | sed -r -n 's/"CurrentBuildNumber"="(.+)"$/\1/p') || { + logerr "Failed to parse CurrentBuildNumber from SOFTWARE hive of '${win_c_partition_devpath}'." + return 1 + } + + ## Windows 11 lies and claims to be Windows 10, but the build + ## number seems to reveal the truth. Windows 11 build numbers + ## start from 22000. + ## + ## https://learn.microsoft.com/en-us/answers/questions/555857/windows-11-product-name-in-registry + ## https://learn.microsoft.com/en-us/windows/release-health/release-information + if [ "${win_build_number}" -ge 22000 ]; then + # This is actually Windows 11. + win_product_name=$(echo -n "${win_product_name}" | sed -r 's/^Windows 10/Windows 11/') + fi + + save_cached_param product_name "$win_product_name" || { + logerr 'Could not save Windows product name to cache' + return 1 + } - printf '%s' "${win_product_name}" + printf '%s' "${win_product_name}" } get_win_product_name() { - local win_c_partition_devpath - win_c_partition_devpath=$1 + local win_c_partition_devpath + win_c_partition_devpath=$1 - if ! get_win_product_name_from_partition "$win_c_partition_devpath"; then - load_cached_param product_name || return 1 - loginfo 'Loaded Windows product name from reset cache' - fi + if ! get_win_product_name_from_partition "$win_c_partition_devpath"; then + load_cached_param product_name || return 1 + loginfo 'Loaded Windows product name from reset cache' + fi - return 0 + return 0 } print0_wim_image_index() { - local win_product_name \ - wim_file_path \ - wim_image_index + local win_product_name \ + wim_file_path \ + wim_image_index - wim_file_path=$1 - shift + wim_file_path=$1 + shift - win_product_name=$1 - shift + win_product_name=$1 + shift - loginfo "Finding WIM image for '${win_product_name}' from '${wim_file_path}'..." + loginfo "Finding WIM image for '${win_product_name}' from '${wim_file_path}'..." - wim_image_index=$(wiminfo "${wim_file_path}" \ - | sed -r -n 's/^Display Name:\s+//p' \ - | grep -n -x "${win_product_name}" \ - | cut -d: -f1) || { - logerr "Failed to find WIM image for '${win_product_name}' from '${wim_file_path}'." - return 1 - } - if ! [ "${wim_image_index}" -ge 1 ]; then - logerr "Failed to find WIM image for '${win_product_name}' from '${wim_file_path}'." - return 1 - fi + wim_image_index=$(wiminfo "${wim_file_path}" \ + | sed -r -n 's/^Display Name:\s+//p' \ + | grep -n -x "${win_product_name}" \ + | cut -d: -f1) || { + logerr "Failed to find WIM image for '${win_product_name}' from '${wim_file_path}'." + return 1 + } + if ! [ "${wim_image_index}" -ge 1 ]; then + logerr "Failed to find WIM image for '${win_product_name}' from '${wim_file_path}'." + return 1 + fi - loginfo "Found WIM image for '${win_product_name}' from '${wim_file_path}' at index ${wim_image_index}." + loginfo "Found WIM image for '${win_product_name}' from '${wim_file_path}' at index ${wim_image_index}." - printf "%d" "${wim_image_index}" + printf "%d" "${wim_image_index}" } verify_wim_image() { - local wim_image_name + local wim_image_name - wim_image_name=$1 + wim_image_name=$1 - loginfo "Verifying WIM file '${wim_image_name}'..." - jq -r --arg wim_image "$wim_image_name" ' + loginfo "Verifying WIM file '${wim_image_name}'..." + jq -r --arg wim_image "$wim_image_name" ' .images[$wim_image].sha512sum + " " + $wim_image ' "$G_WIM_CATALOGUE_PATH" \ - | sha512sum --strict --status -c || { - logerr "Failed to verify WIM file '${wim_image_name}'." - return 1 - } - loginfo "Verified WIM file '${wim_image_name}'." + | sha512sum --strict --status -c || { + logerr "Failed to verify WIM file '${wim_image_name}'." + return 1 + } + loginfo "Verified WIM file '${wim_image_name}'." } fetch_wim_image_from_filesystem() { - local json_string_puavo_wim_images_fs_devpath \ - puavo_wim_images_fs_devpath \ - puavo_wim_images_mountpoint \ - target_wim_file_path \ - wim_image_name - - wim_image_name=$1 - shift - - target_wim_file_path=$(readlink -f "$wim_image_name") - - while read -r json_string_puavo_wim_images_fs_devpath; do - puavo_wim_images_fs_devpath=$(jq -j -n "$json_string_puavo_wim_images_fs_devpath") - if [ -n "$puavo_wim_images_fs_devpath" ]; then - loginfo "Found Puavo WIM images filesystem from '${puavo_wim_images_fs_devpath}'. Mounting it..." - - # .mountpoint dirs are automagically umounted on_exit - puavo_wim_images_mountpoint=$(mktemp -d -p . puavo_wim_images.XXXXXXXXXX.mountpoint) || { - logwarning 'Failed to create a mount point for Puavo WIM images filesystem! Really strange, but not fatal. Perhaps WIM images can be found elsewhere.' - continue - } - mount -o ro,nodev,nosuid "$puavo_wim_images_fs_devpath" "$puavo_wim_images_mountpoint" || { - logwarning 'Failed to mount Puavo WIM images filesystem. Not fatal, continuing the search for WIM images.' - continue # Perhaps there's another Puavo WIM images filesystem. - } - loginfo "Mounted Puavo WIM images filesystem from '${puavo_wim_images_fs_devpath}' to '${puavo_wim_images_mountpoint}'." - fi - done < <(lsblk -J -o LABEL,PATH,MOUNTPOINT,FSTYPE \ - | jq '.blockdevices[] | select(.label == "Puavo WIM images" and .mountpoint == null and .fstype == "ext4").path') - - while read -r json_string_mountpoint; do - ## This is the moment when I wish I had used Python instead. - ## All this juggling because of the theoretical case the - ## mountpoint contains newline characters: so first we parse - ## lsblk's output JSON while being aware that mountpoint might - ## have newline chars, that's why we output it as JSON string - ## instead and then parse each JSON string separately to avoid - ## splitting. I don't know how this could be done easier (jq - ## does not have printf, it does not have nul-delimited - ## output). - mountpoint=$(jq -j -n "$json_string_mountpoint") - - while IFS= read -r -d $'\0' source_wim_file_path; do - if [ "$source_wim_file_path" = "$target_wim_file_path" ]; then - continue - fi - ## A bit optimistic approach: assume the source file is - ## ok. It will be verified in the upper layer, but if it's - ## invalid, then there's nothing the upper layer can do - ## about it anymore. It would be better if this function - ## could just go on and look for other files, but I don't - ## know if it's worth the effort. In practice, there will - ## be just one win10x64.iso out there, if any. - loginfo "Fetching WIM file '${wim_image_name}' from '${source_wim_file_path}'..." - install -m 0644 "$source_wim_file_path" "$target_wim_file_path" || { - logerr "Failed to fetch WIM file '${wim_image_name}' from '${source_wim_file_path}'." - return 1 - } - loginfo "Fetched WIM file '${wim_image_name}' from '${source_wim_file_path}'." - return 0 - done < <(find "$mountpoint" -type f -name "$wim_image_name" -print0) - - done < <(lsblk -J -o MOUNTPOINT,FSTYPE \ - | jq '.blockdevices[] | select(.mountpoint and (.fstype == "exfat" or .fstype == "ext4" or .fstype == "ntfs")).mountpoint') + local json_string_puavo_wim_images_fs_devpath \ + puavo_wim_images_fs_devpath \ + puavo_wim_images_mountpoint \ + target_wim_file_path \ + wim_image_name + + wim_image_name=$1 + shift + + target_wim_file_path=$(readlink -f "$wim_image_name") + + while read -r json_string_puavo_wim_images_fs_devpath; do + puavo_wim_images_fs_devpath=$(jq -j -n "$json_string_puavo_wim_images_fs_devpath") + if [ -n "$puavo_wim_images_fs_devpath" ]; then + loginfo "Found Puavo WIM images filesystem from '${puavo_wim_images_fs_devpath}'. Mounting it..." + + # .mountpoint dirs are automagically umounted on_exit + puavo_wim_images_mountpoint=$(mktemp -d -p . puavo_wim_images.XXXXXXXXXX.mountpoint) || { + logwarning 'Failed to create a mount point for Puavo WIM images filesystem! Really strange, but not fatal. Perhaps WIM images can be found elsewhere.' + continue + } + mount -o ro,nodev,nosuid "$puavo_wim_images_fs_devpath" "$puavo_wim_images_mountpoint" || { + logwarning 'Failed to mount Puavo WIM images filesystem. Not fatal, continuing the search for WIM images.' + continue # Perhaps there's another Puavo WIM images filesystem. + } + loginfo "Mounted Puavo WIM images filesystem from '${puavo_wim_images_fs_devpath}' to '${puavo_wim_images_mountpoint}'." + fi + done < <(lsblk -J -o LABEL,PATH,MOUNTPOINT,FSTYPE \ + | jq '.blockdevices[] | select(.label == "Puavo WIM images" and .mountpoint == null and .fstype == "ext4").path') + + while read -r json_string_mountpoint; do + ## This is the moment when I wish I had used Python instead. + ## All this juggling because of the theoretical case the + ## mountpoint contains newline characters: so first we parse + ## lsblk's output JSON while being aware that mountpoint might + ## have newline chars, that's why we output it as JSON string + ## instead and then parse each JSON string separately to avoid + ## splitting. I don't know how this could be done easier (jq + ## does not have printf, it does not have nul-delimited + ## output). + mountpoint=$(jq -j -n "$json_string_mountpoint") + + while IFS= read -r -d $'\0' source_wim_file_path; do + if [ "$source_wim_file_path" = "$target_wim_file_path" ]; then + continue + fi + ## A bit optimistic approach: assume the source file is + ## ok. It will be verified in the upper layer, but if it's + ## invalid, then there's nothing the upper layer can do + ## about it anymore. It would be better if this function + ## could just go on and look for other files, but I don't + ## know if it's worth the effort. In practice, there will + ## be just one win10x64.iso out there, if any. + loginfo "Fetching WIM file '${wim_image_name}' from '${source_wim_file_path}'..." + install -m 0644 "$source_wim_file_path" "$target_wim_file_path" || { + logerr "Failed to fetch WIM file '${wim_image_name}' from '${source_wim_file_path}'." + return 1 + } + loginfo "Fetched WIM file '${wim_image_name}' from '${source_wim_file_path}'." + return 0 + done < <(find "$mountpoint" -type f -name "$wim_image_name" -print0) - return 1 + done < <(lsblk -J -o MOUNTPOINT,FSTYPE \ + | jq '.blockdevices[] | select(.mountpoint and (.fstype == "exfat" or .fstype == "ext4" or .fstype == "ntfs")).mountpoint') + + return 1 } fetch_wim_image_from_server() { - local wim_image_baseurl wim_image_name wim_image_url wim_tmppath + local wim_image_baseurl wim_image_name wim_image_url wim_tmppath - wim_image_baseurl=$1 - wim_image_name=$2 + wim_image_baseurl=$1 + wim_image_name=$2 - wim_image_url="${wim_image_baseurl}/${wim_image_name}" - wim_tmppath="${wim_image_name}.tmp" + wim_image_url="${wim_image_baseurl}/${wim_image_name}" + wim_tmppath="${wim_image_name}.tmp" - loginfo "Fetching WIM image from ${wim_image_url}" + loginfo "Fetching WIM image from ${wim_image_url}" - if ! wget_with_certauth --output-document "$wim_tmppath" \ - -q --progress=dot:giga --show-progress "$wim_image_url"; then - logerr "Failed to fetch WIM image ${wim_image_name}" - return 1 - fi + if ! wget_with_certauth --output-document "$wim_tmppath" \ + -q --progress=dot:giga --show-progress "$wim_image_url"; then + logerr "Failed to fetch WIM image ${wim_image_name}" + return 1 + fi - mv "$wim_tmppath" "$wim_image_name" || return 1 + mv "$wim_tmppath" "$wim_image_name" || return 1 - loginfo "Fetched WIM image from ${wim_image_name}" + loginfo "Fetched WIM image from ${wim_image_name}" } fetch_wim_image() { - local wim_image_baseurl wim_image_name + local wim_image_baseurl wim_image_name - wim_image_baseurl=$1 - wim_image_name=$2 + wim_image_baseurl=$1 + wim_image_name=$2 - loginfo "Fetching WIM file '${wim_image_name}'..." + loginfo "Fetching WIM file '${wim_image_name}'..." - if [ -f "$wim_image_name" ]; then - loginfo "WIM file '${wim_image_name}' already exists." - if verify_wim_image "$wim_image_name"; then - return 0 - fi - loginfo "Existing WIM file '${wim_image_name}' is invalid. Re-fetching it." + if [ -f "$wim_image_name" ]; then + loginfo "WIM file '${wim_image_name}' already exists." + if verify_wim_image "$wim_image_name"; then + return 0 fi + loginfo "Existing WIM file '${wim_image_name}' is invalid. Re-fetching it." + fi - if fetch_wim_image_from_filesystem "$wim_image_name"; then - loginfo "Fetched WIM file '${wim_image_name}' from a local filesystem." - if verify_wim_image "$wim_image_name"; then - return 0 - fi - else - loginfo "Could not find '${wim_image_name}' from local filesystems." + if fetch_wim_image_from_filesystem "$wim_image_name"; then + loginfo "Fetched WIM file '${wim_image_name}' from a local filesystem." + if verify_wim_image "$wim_image_name"; then + return 0 fi + else + loginfo "Could not find '${wim_image_name}' from local filesystems." + fi - ## TODO: Implement other fetch functions: - ## - from bootserver + ## TODO: Implement other fetch functions: + ## - from bootserver - fetch_wim_image_from_server "$wim_image_baseurl" "$wim_image_name" || { - logerr "Failed to fetch WIM file '${wim_image_name}'." - return 1 - } + fetch_wim_image_from_server "$wim_image_baseurl" "$wim_image_name" || { + logerr "Failed to fetch WIM file '${wim_image_name}'." + return 1 + } - loginfo "Fetched WIM file '${wim_image_name}'." + loginfo "Fetched WIM file '${wim_image_name}'." - verify_wim_image "$wim_image_name" + verify_wim_image "$wim_image_name" } wget_with_certauth() { - wget --ca-certificate=/etc/puavo-conf/rootca.pem \ - --certificate=/etc/puavo/certs/hostorgcabundle.pem \ - --private-key=/etc/puavo/certs/host.key \ - "$@" + wget --ca-certificate=/etc/puavo-conf/rootca.pem \ + --certificate=/etc/puavo/certs/hostorgcabundle.pem \ + --private-key=/etc/puavo/certs/host.key \ + "$@" } get_wim_catalogue() { - local gnupg_dir wim_image_source_urls wim_gpg_tmppath wim_path \ - wim_server wim_tmppath - - wim_image_source_urls=$(puavo-conf puavo.windows.image.sources) - - wim_gpg_tmppath="${G_WIM_CATALOGUE_PATH}.gpg.tmp" - wim_tmppath="${G_WIM_CATALOGUE_PATH}.tmp" - - for url in $wim_image_source_urls; do - if ! wget_with_certauth -q \ - --output-document "$wim_gpg_tmppath" "$url"; then - echo "error fetching $url" >&2 - continue - fi - - wim_server=$(dirname "${url#https://}") - gnupg_dir="/root/.puavo/gnupg/${wim_server}/wim" - if ! gpg --decrypt --homedir "$gnupg_dir" "$wim_gpg_tmppath" \ - 2>/dev/null > "$wim_tmppath"; then - echo "GPG verification failed for ${url}" >&2 - continue - fi - - mv "$wim_tmppath" "$G_WIM_CATALOGUE_PATH" || return 1 - printf "%s/images" "${url%/*}" || return 1 - return 0 - done - - echo 'could not fetch any source in puavo.windows.image.sources' >&2 - return 1 + local gnupg_dir wim_image_source_urls wim_gpg_tmppath wim_path \ + wim_server wim_tmppath + + wim_image_source_urls=$(puavo-conf puavo.windows.image.sources) + + wim_gpg_tmppath="${G_WIM_CATALOGUE_PATH}.gpg.tmp" + wim_tmppath="${G_WIM_CATALOGUE_PATH}.tmp" + + for url in $wim_image_source_urls; do + if ! wget_with_certauth -q \ + --output-document "$wim_gpg_tmppath" "$url"; then + echo "error fetching $url" >&2 + continue + fi + + wim_server=$(dirname "${url#https://}") + gnupg_dir="/root/.puavo/gnupg/${wim_server}/wim" + if ! gpg --decrypt --homedir "$gnupg_dir" "$wim_gpg_tmppath" \ + 2>/dev/null > "$wim_tmppath"; then + echo "GPG verification failed for ${url}" >&2 + continue + fi + + mv "$wim_tmppath" "$G_WIM_CATALOGUE_PATH" || return 1 + printf "%s/images" "${url%/*}" || return 1 + return 0 + done + + echo 'could not fetch any source in puavo.windows.image.sources' >&2 + return 1 } choose_wim_image_to_use() { - local preferred_version_count preferred_versions win_language \ - win_product_name win_version - - win_language=$1 - win_product_name=$2 - - case "$win_product_name" in - 'Windows 10 '*) win_version="Win10" ;; - 'Windows 11 '*) win_version="Win11" ;; - *) - logerr "Unexpected Windows product name '${win_product_name}'" - return 1 - ;; - esac - - preferred_versions=$( - jq -r --arg language "$win_language" \ - --arg version "$win_version" ' + local preferred_version_count preferred_versions win_language \ + win_product_name win_version + + win_language=$1 + win_product_name=$2 + + case "$win_product_name" in + 'Windows 10 '*) win_version="Win10" ;; + 'Windows 11 '*) win_version="Win11" ;; + *) + logerr "Unexpected Windows product name '${win_product_name}'" + return 1 + ;; + esac + + preferred_versions=$( + jq -r --arg language "$win_language" \ + --arg version "$win_version" ' .images | map_values(select(.language == $language and .version == $version)) | to_entries | map(.key) | .[] @@ -525,188 +525,188 @@ choose_wim_image_to_use() return 1 } - preferred_version_count="$(printf "%s\n" "$preferred_versions" | wc -l)" + preferred_version_count="$(printf "%s\n" "$preferred_versions" | wc -l)" - if [ "$preferred_version_count" -gt 1 ]; then - logerr "Multiple image options with ${win_version} and ${win_language}" - return 1 - elif [ "$preferred_version_count" -lt 1 ]; then - logerr "No image available with ${win_version} and ${win_language}" - return 1 - fi + if [ "$preferred_version_count" -gt 1 ]; then + logerr "Multiple image options with ${win_version} and ${win_language}" + return 1 + elif [ "$preferred_version_count" -lt 1 ]; then + logerr "No image available with ${win_version} and ${win_language}" + return 1 + fi - printf "%s\n" "$preferred_versions" + printf "%s\n" "$preferred_versions" } install_win() { - local wim_image_baseurl wim_image_name win_language \ - win_c_partition_devpath win_product_name + local wim_image_baseurl wim_image_name win_language \ + win_c_partition_devpath win_product_name - win_product_name=$1 - shift + win_product_name=$1 + shift - win_language=$1 - shift + win_language=$1 + shift - win_c_partition_devpath=$1 - shift + win_c_partition_devpath=$1 + shift - wim_image_baseurl=$(get_wim_catalogue) || return 1 + wim_image_baseurl=$(get_wim_catalogue) || return 1 - wim_image_name=$(choose_wim_image_to_use "$win_language" \ - "$win_product_name") + wim_image_name=$(choose_wim_image_to_use "$win_language" \ + "$win_product_name") - loginfo "Installing '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'..." + loginfo "Installing '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'..." - fetch_wim_image "$wim_image_baseurl" "$wim_image_name" || { - logerr "Failed to fetch WIM file for '${win_product_name} (${win_language})'." - return 1 - } + fetch_wim_image "$wim_image_baseurl" "$wim_image_name" || { + logerr "Failed to fetch WIM file for '${win_product_name} (${win_language})'." + return 1 + } - wim_image_index=$(print0_wim_image_index "$wim_image_name" "$win_product_name") + wim_image_index=$(print0_wim_image_index "$wim_image_name" "$win_product_name") - loginfo "Securely erasing '${win_c_partition_devpath}'" - blkdiscard "${win_c_partition_devpath}" || { - logerr "Failed to run blkdiscard to '${win_c_partition_devpath}'" - return 1 - } - loginfo "Secure erase done." + loginfo "Securely erasing '${win_c_partition_devpath}'" + blkdiscard "${win_c_partition_devpath}" || { + logerr "Failed to run blkdiscard to '${win_c_partition_devpath}'" + return 1 + } + loginfo "Secure erase done." - loginfo "Creating NTFS filesystem on '${win_c_partition_devpath}'..." - # Force needed to overwrite the existing filesystem without questions. - mkfs.ntfs -f "${win_c_partition_devpath}" || { - logerr "Failed to create NTFS filesystem on '${win_c_partition_devpath}'" - return 1 - } - loginfo "Created NTFS filesystem on '${win_c_partition_devpath}'." + loginfo "Creating NTFS filesystem on '${win_c_partition_devpath}'..." + # Force needed to overwrite the existing filesystem without questions. + mkfs.ntfs -f "${win_c_partition_devpath}" || { + logerr "Failed to create NTFS filesystem on '${win_c_partition_devpath}'" + return 1 + } + loginfo "Created NTFS filesystem on '${win_c_partition_devpath}'." - loginfo "Applying WIM image to '${win_c_partition_devpath}'..." - wimapply "${wim_image_name}" "${wim_image_index}" "${win_c_partition_devpath}" || { - logerr "Failed to apply WIM image '${wim_image_index}' from '${wim_image_name}' to '${win_c_partition_devpath}'." - return 1 - } - loginfo "Applied WIM image to '${win_c_partition_devpath}'." + loginfo "Applying WIM image to '${win_c_partition_devpath}'..." + wimapply "${wim_image_name}" "${wim_image_index}" "${win_c_partition_devpath}" || { + logerr "Failed to apply WIM image '${wim_image_index}' from '${wim_image_name}' to '${win_c_partition_devpath}'." + return 1 + } + loginfo "Applied WIM image to '${win_c_partition_devpath}'." - loginfo "Installed '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' to factory settings successfully." + loginfo "Installed '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' to factory settings successfully." - return 0 + return 0 } get_win_language_from_puavo_conf() { - local puavo_language win_language - - puavo_language=$(puavo-conf puavo.l10n.locale | cut -c 1-2 || true) - - case "${puavo_language}" in - 'fi') - win_language='Finnish' - ;; - 'sv') - win_language='Swedish' - ;; - 'de') - win_language='German' - ;; - *) - win_language='English' - ;; - esac - - printf '%s' "${win_language}" + local puavo_language win_language + + puavo_language=$(puavo-conf puavo.l10n.locale | cut -c 1-2 || true) + + case "${puavo_language}" in + 'fi') + win_language='Finnish' + ;; + 'sv') + win_language='Swedish' + ;; + 'de') + win_language='German' + ;; + *) + win_language='English' + ;; + esac + + printf '%s' "${win_language}" } reset_win() { - local win_c_partition_devpath win_language win_product_name - - win_c_partition_devpath=$1 - shift - - win_product_name=$(get_win_product_name "${win_c_partition_devpath}") || { - logerr "Failed to get the product name of Windows on '${win_c_partition_devpath}'." - win_product_name='Windows 11 Pro' - logwarning "Using '${win_product_name}' as a fallback." + local win_c_partition_devpath win_language win_product_name + + win_c_partition_devpath=$1 + shift + + win_product_name=$(get_win_product_name "${win_c_partition_devpath}") || { + logerr "Failed to get the product name of Windows on '${win_c_partition_devpath}'." + win_product_name='Windows 11 Pro' + logwarning "Using '${win_product_name}' as a fallback." + } + + win_language=$(get_win_language "${win_c_partition_devpath}") || { + logerr "Failed to get the language tag of Windows on '${win_c_partition_devpath}'." + win_language="$(get_win_language_from_puavo_conf)" || { + logerr 'Failed to get fallback Windows language from Puavo configuration, which should never happen!' + win_language='English' } + logwarning "Using '${win_language}' as a fallback." + } - win_language=$(get_win_language "${win_c_partition_devpath}") || { - logerr "Failed to get the language tag of Windows on '${win_c_partition_devpath}'." - win_language="$(get_win_language_from_puavo_conf)" || { - logerr 'Failed to get fallback Windows language from Puavo configuration, which should never happen!' - win_language='English' - } - logwarning "Using '${win_language}' as a fallback." - } - - loginfo "Detected '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + loginfo "Detected '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - $g_use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ - "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'?" 5 100 || { - loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - return 0 + $g_use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ + "Reset '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'?" 5 100 || { + loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + return 0 } - $g_use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ - "All data will be lost on '${win_c_partition_devpath}'! Are you really sure you want to proceed?" 5 100 || { - loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - return 0 + $g_use_force || dialog --no-lines --clear --erase-on-exit --defaultno --yesno \ + "All data will be lost on '${win_c_partition_devpath}'! Are you really sure you want to proceed?" 5 100 || { + loginfo "Skipping '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + return 0 } - install_win "${win_product_name}" "${win_language}" "${win_c_partition_devpath}" || { - logerr "Failed to install '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." - return 1 - } + install_win "${win_product_name}" "${win_language}" "${win_c_partition_devpath}" || { + logerr "Failed to install '${win_product_name} (${win_language})' on '${win_c_partition_devpath}'." + return 1 + } - loginfo "Windows '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' reset to factory defaults." + loginfo "Windows '${win_product_name} (${win_language})' on '${win_c_partition_devpath}' reset to factory defaults." - return 0 + return 0 } reset_all_wins() { - local returnval win_c_partition_devpath - - returnval=0 - - while IFS= read -r -d $'\0' win_c_partition_devpath; do - if [ -z "${g_win_c_partition_devpath}" -o "${g_win_c_partition_devpath}" = "${win_c_partition_devpath}" ]; then - reset_win "${win_c_partition_devpath}" || { - returnval=1 - } - fi - done < <(print0_win_c_partition_devpaths) || { - logerr "Unexpected termination of Windows reset loop" + local returnval win_c_partition_devpath + + returnval=0 + + while IFS= read -r -d $'\0' win_c_partition_devpath; do + if [ -z "${g_win_c_partition_devpath}" -o "${g_win_c_partition_devpath}" = "${win_c_partition_devpath}" ]; then + reset_win "${win_c_partition_devpath}" || { returnval=1 - } + } + fi + done < <(print0_win_c_partition_devpaths) || { + logerr "Unexpected termination of Windows reset loop" + returnval=1 + } - return $returnval + return $returnval } while [ $# -ne 0 ]; do - case "$1" in - --force) - g_use_force=true - shift - ;; - --) - shift - break - ;; - -*) - logerr "invalid argument '$1'" - usage - ;; - *) - break - ;; - esac + case "$1" in + --force) + g_use_force=true + shift + ;; + --) + shift + break + ;; + -*) + logerr "invalid argument '$1'" + usage + ;; + *) + break + ;; + esac done if [ $# -eq 1 ]; then - g_win_c_partition_devpath=$1 - shift + g_win_c_partition_devpath=$1 + shift fi [ $# -eq 0 ] || usage @@ -718,8 +718,8 @@ fi exec {g_lockfd}<> "${G_PID_FILE}" flock -x -n "${g_lockfd}" || { - logerr "puavo-reset-windows is already running!" - exit 1 + logerr "puavo-reset-windows is already running!" + exit 1 } trap on_exit EXIT From e8c4304be88080f28388721804bb22078a66bbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuomas=20R=C3=A4s=C3=A4nen?= Date: Tue, 8 Oct 2024 19:28:45 +0300 Subject: [PATCH 8/9] puavo-reset-windows: [refactor] fix not-well defined construct --- parts/ltsp/puavo-install/puavo-reset-windows | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index dd153a97ec..087616b24d 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -671,7 +671,7 @@ reset_all_wins() returnval=0 while IFS= read -r -d $'\0' win_c_partition_devpath; do - if [ -z "${g_win_c_partition_devpath}" -o "${g_win_c_partition_devpath}" = "${win_c_partition_devpath}" ]; then + if [ -z "${g_win_c_partition_devpath}" ] || [ "${g_win_c_partition_devpath}" = "${win_c_partition_devpath}" ]; then reset_win "${win_c_partition_devpath}" || { returnval=1 } From b101d4bb0c627c8bf5eedea0a041d59d581f0c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuomas=20R=C3=A4s=C3=A4nen?= Date: Tue, 8 Oct 2024 19:29:14 +0300 Subject: [PATCH 9/9] puavo-reset-windows: [refactor] remove unused local definition --- parts/ltsp/puavo-install/puavo-reset-windows | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parts/ltsp/puavo-install/puavo-reset-windows b/parts/ltsp/puavo-install/puavo-reset-windows index 087616b24d..3e8d32cf02 100755 --- a/parts/ltsp/puavo-install/puavo-reset-windows +++ b/parts/ltsp/puavo-install/puavo-reset-windows @@ -465,7 +465,7 @@ wget_with_certauth() get_wim_catalogue() { - local gnupg_dir wim_image_source_urls wim_gpg_tmppath wim_path \ + local gnupg_dir wim_image_source_urls wim_gpg_tmppath \ wim_server wim_tmppath wim_image_source_urls=$(puavo-conf puavo.windows.image.sources)