feat: Improve error handling (#2120)

This commit is contained in:
Kroese
2026-08-09 02:46:04 +02:00
committed by GitHub
parent 33ae12677e
commit 19264a42da
5 changed files with 424 additions and 145 deletions
+107 -39
View File
@@ -30,10 +30,21 @@ updateXML() {
[ -z "${HEIGHT:-}" ] && HEIGHT="720" [ -z "${HEIGHT:-}" ] && HEIGHT="720"
validateXMLSettings || return 1 validateXMLSettings || return 1
ensureXMLDefaultNamespace "$asset" || return 1
updateUserXML "$asset" || return 1 if ! ensureXMLDefaultNamespace "$asset"; then
updateLocaleXML "$asset" "$language" || return 1 error "Failed to prepare the answer file XML namespace!"
return 1
fi
if ! updateUserXML "$asset"; then
error "Failed to update user and display settings in answer file!"
return 1
fi
if ! updateLocaleXML "$asset" "$language"; then
error "Failed to update regional settings in answer file!"
return 1
fi
if [ -n "$domain" ]; then if [ -n "$domain" ]; then
@@ -46,13 +57,24 @@ updateXML() {
else else
updateLocalAccount "$asset" || return 1 if ! updateLocalAccount "$asset"; then
error "Failed to update local account settings in answer file!"
return 1
fi
fi fi
updateMembership "$asset" "$domain" "$workgroup" "$account" "$auth" || return 1 updateMembership "$asset" "$domain" "$workgroup" "$account" "$auth" || return 1
updateAutologinXML "$asset" || return 1
updateEditionXML "$asset" || return 1 if ! updateAutologinXML "$asset"; then
error "Failed to update automatic logon settings in answer file!"
return 1
fi
if ! updateEditionXML "$asset"; then
error "Failed to update edition settings in answer file!"
return 1
fi
validateGeneratedXML "$asset" || return 1 validateGeneratedXML "$asset" || return 1
@@ -73,7 +95,7 @@ setXML() {
if [ -d "${custom_files[0]}" ]; then if [ -d "${custom_files[0]}" ]; then
error "The bind ${custom_files[0]} maps to a file that does not exist!" error "The bind ${custom_files[0]} maps to a file that does not exist!"
exit 67 return 2
fi fi
# A custom answer file always takes precedence over bundled or generated # A custom answer file always takes precedence over bundled or generated
@@ -182,7 +204,7 @@ addAnswerFile() {
if ! updateDiskID "$answer" "${DISK_TYPE:-}"; then if ! updateDiskID "$answer" "${DISK_TYPE:-}"; then
error "Failed to adjust the Windows installation disk!" error "Failed to adjust the Windows installation disk!"
exit 85 return 1
fi fi
if ! setConfigurationXML "$answer"; then if ! setConfigurationXML "$answer"; then
@@ -194,7 +216,10 @@ addAnswerFile() {
if [ -z "${CUSTOM_XML:-}" ]; then if [ -z "${CUSTOM_XML:-}" ]; then
prepareSetupScript "$asset" "$stage" || exit 84 if ! prepareSetupScript "$asset" "$stage"; then
error "Failed to prepare the Windows setup script!"
return 1
fi
fi fi
@@ -1080,7 +1105,13 @@ updateDiskID() {
done <<< "$values" done <<< "$values"
mapfile -t ids < <(printf '%s\n' "${ids[@]}" | sort -u) local unique
unique=$(printf '%s\n' "${ids[@]}" | sort -u) || {
error "Failed to normalize DiskID values from answer file: $asset"
return 1
}
mapfile -t ids <<< "$unique"
# Leave explicit multi-disk configurations untouched. # Leave explicit multi-disk configurations untouched.
(( ${#ids[@]} == 1 )) || return 0 (( ${#ids[@]} == 1 )) || return 0
@@ -1946,10 +1977,16 @@ markGeneratedXML() {
local file="$1" local file="$1"
local marker='<!-- generated-answer-file: do not reuse as a template -->' local marker='<!-- generated-answer-file: do not reuse as a template -->'
local first
[ -s "$file" ] || return 1 [ -s "$file" ] || return 1
if head -n 1 "$file" | grep -q '^<?xml'; then if ! first=$(head -n 1 "$file"); then
error "Failed to inspect generated answer file: $file"
return 1
fi
if [[ "$first" == "<?xml"* ]]; then
sed -i "1a$marker" "$file" || return 1 sed -i "1a$marker" "$file" || return 1
else else
sed -i "1i$marker" "$file" || return 1 sed -i "1i$marker" "$file" || return 1
@@ -1961,12 +1998,17 @@ markGeneratedXML() {
removeGeneratedXML() { removeGeneratedXML() {
local file="$1" local file="$1"
local header
[ -n "$file" ] || return 0 [ -n "$file" ] || return 0
[ -f "$file" ] || return 0 [ -f "$file" ] || return 0
head -n 5 "$file" | if ! header=$(head -n 5 "$file"); then
grep -Fqi 'generated-answer-file' || return 0 error "Failed to inspect answer file: $file"
return 1
fi
grep -Fqi 'generated-answer-file' <<< "$header" || return 0
if ! rm -f "$file"; then if ! rm -f "$file"; then
error "Failed to remove generated answer file: $file" error "Failed to remove generated answer file: $file"
@@ -2323,10 +2365,18 @@ addSIFEntry() {
return 1 return 1
fi fi
if grep -Fqx "$entry" "$file" || grep -Fqx "$entry"$'\r' "$file"; then local rc=0
grep -Fqx -e "$entry" -e "$entry"$'\r' "$file" || rc=$?
if (( rc == 0 )); then
return 0 return 0
fi fi
if (( rc != 1 )); then
error "Failed to inspect section \"$header\" in \"$file\" !"
return 1
fi
if [[ "$ending" == "crlf" ]]; then if [[ "$ending" == "crlf" ]]; then
printf '%s\r\n' "$entry" printf '%s\r\n' "$entry"
else else
@@ -2412,7 +2462,9 @@ addLegacyDrivers() {
patchStorageDriver "$file" "$arch" || return 1 patchStorageDriver "$file" "$arch" || return 1
addSataDriver "$dir" "$target" "$arch" "$drivers" "$file" || return 1 addSataDriver "$dir" "$target" "$arch" "$drivers" "$file" || return 1
rm -rf "$drivers" || return 1 if ! rm -rf "$drivers"; then
warn "failed to clean temporary driver files!"
fi
return 0 return 0
} }
@@ -2424,7 +2476,7 @@ setLegacyKey() {
local arch="$3" local arch="$3"
local desc="$4" local desc="$4"
local setup pid key file local setup pid file block
setup=$(find "$target" -maxdepth 1 -type f -iname setupp.ini -print -quit) || return 1 setup=$(find "$target" -maxdepth 1 -type f -iname setupp.ini -print -quit) || return 1
[[ -n "$setup" ]] || return 0 [[ -n "$setup" ]] || return 0
@@ -2434,7 +2486,8 @@ setLegacyKey() {
pid="${pid%$'\r'}" pid="${pid%$'\r'}"
if [[ "$driver" == "2k" ]]; then if [[ "$driver" == "2k" ]]; then
echo "${pid::-3}270" > "$setup" || return 1 [ "${#pid}" -ge 3 ] || return 0
echo "${pid::-3}270" > "$setup" || :
return 0 return 0
fi fi
@@ -2447,28 +2500,44 @@ setLegacyKey() {
if [[ -n "$file" ]]; then if [[ -n "$file" ]]; then
local key=""
# Prefer a staging or OEM key already shipped on the media before falling # Prefer a staging or OEM key already shipped on the media before falling
# back to Microsoft's documented generic installation keys. # back to Microsoft's documented generic installation keys.
if [[ "$driver" == "2k3" ]]; then if [[ "$driver" == "2k3" ]]; then
key=$(grep -i -A 2 "StagingKey" "$file" | tail -n 2 | head -n 1) || key="" block=$(grep -i -A 2 "StagingKey" "$file") || block=""
if [ -n "$block" ]; then
key=$(printf '%s\n' "$block" | tail -n 2 | head -n 1) || key=""
fi
else else
key="${pid: -8:5}" key="${pid: -8:5}"
if [[ "${pid^^}" == *"OEM" ]]; then if [[ "${pid^^}" == *"OEM" ]]; then
key=$(grep -i -A 2 "$key" "$file" | tail -n 2 | head -n 1) || key=""
block=$(grep -i -A 2 "$key" "$file") || block=""
else else
key=$(grep -i -m 1 -A 2 "$key" "$file" | tail -n 2 | head -n 1) || key=""
block=$(grep -i -m 1 -A 2 "$key" "$file") || block=""
fi
if [ -n "$block" ]; then
key=$(printf '%s\n' "$block" | tail -n 2 | head -n 1) || key=""
fi fi
key="${key#*= }" key="${key#*= }"
fi fi
key="${key%$'\r'}" if [ -n "$key" ]; then
[[ "${#key}" == "29" ]] && KEY="$key" key="${key%$'\r'}"
[[ "${#key}" == "29" ]] && KEY="$key"
fi
fi fi
@@ -2499,7 +2568,9 @@ setLegacyKey() {
esac esac
echo "${pid::-3}000" > "$setup" || return 1 if [ "${#pid}" -ge 3 ]; then
echo "${pid::-3}000" > "$setup" || :
fi
return 0 return 0
} }
@@ -2768,12 +2839,10 @@ disableAutoReboot() {
local target="$1" local target="$1"
local file local file rc=0
local pattern='^[[:space:]]*HKLM[[:space:]]*,[[:space:]]*"SYSTEM\\CurrentControlSet\\Control\\CrashControl"[[:space:]]*,[[:space:]]*"AutoReboot"[[:space:]]*,[[:space:]]*[^,]*,' local pattern='^[[:space:]]*HKLM[[:space:]]*,[[:space:]]*"SYSTEM\\CurrentControlSet\\Control\\CrashControl"[[:space:]]*,[[:space:]]*"AutoReboot"[[:space:]]*,[[:space:]]*[^,]*,'
file=$(find \ file=$(find "$target" -maxdepth 1 -type f -iname HIVESYS.INF -print -quit) || return 1
"$target" -maxdepth 1 -type f -iname HIVESYS.INF -print -quit
) || return 1
if [ -z "$file" ]; then if [ -z "$file" ]; then
error "The file HIVESYS.INF could not be found!" error "The file HIVESYS.INF could not be found!"
@@ -2782,19 +2851,18 @@ disableAutoReboot() {
# Keep setup crashes visible instead of immediately rebooting into an # Keep setup crashes visible instead of immediately rebooting into an
# opaque installation loop. # opaque installation loop.
if grep -Eqi "${pattern}[[:space:]]*[^,;[:space:]]+" "$file"; then grep -Eqi "${pattern}[[:space:]]*[^,;[:space:]]+" "$file" || rc=$?
sed -i -E \ case "$rc" in
"s|(${pattern})[[:space:]]*[^,;[:space:]]+|\\1 0|I" \ 0 )
"$file" || return 1 sed -i -E "s|(${pattern})[[:space:]]*[^,;[:space:]]+|\\1 0|I" "$file" || :
;;
else 1 )
printf '%s\n' \
printf '%s\n' \ 'HKLM,"SYSTEM\CurrentControlSet\Control\CrashControl","AutoReboot",0x00010001,0' |
'HKLM,"SYSTEM\CurrentControlSet\Control\CrashControl","AutoReboot",0x00010001,0' | unix2dos >> "$file" || :
unix2dos >> "$file" || return 1 ;;
esac
fi
return 0 return 0
} }
+41 -23
View File
@@ -647,23 +647,28 @@ getVersion() {
local evaluation="" local evaluation=""
id=$(fromName "$name" "$arch") id=$(fromName "$name" "$arch")
[ -z "$id" ] && return 0
[[ "${name,,}" == *"evaluation"* ]] && evaluation="-eval" [[ "${name,,}" == *"evaluation"* ]] && evaluation="-eval"
case "${id,,}" in case "${id,,}" in
"winvista"* | "win7"* | "win8"* | "win10"* | "win11"* )
if edition=$(getEditionID "$name" "$id"); then
[ -n "$edition" ] && id+="-$edition"
[ -n "$evaluation" ] && id+="$evaluation"
fi
;;
"win20"* ) "win20"* )
if [[ "${name,,}" == *"hyper-v server"* ]]; then if [[ "${name,,}" == *"hyper-v server"* ]]; then
id+="-hv" id+="-hv"
elif edition=$(getServerEditionID "$name" "$id"); then elif edition=$(getServerEditionID "$name" "$id"); then
[ -n "$edition" ] && id+="-$edition" [ -n "$edition" ] && id+="-$edition"
[ -n "$evaluation" ] && id+="$evaluation" [ -n "$evaluation" ] && id+="$evaluation"
fi fi ;;
;;
* )
if edition=$(getEditionID "$name" "$id"); then
[ -n "$edition" ] && id+="-$edition"
[ -n "$evaluation" ] && id+="$evaluation"
fi ;;
esac esac
echo "$id" echo "$id"
@@ -695,6 +700,7 @@ getEditionRank() {
case "$base" in case "$base" in
"win20"* ) "win20"* )
case "$edition" in case "$edition" in
"" ) echo 0 ;; "" ) echo 0 ;;
"datacenter-azure-core" | "datacenter-azure-core-"* | \ "datacenter-azure-core" | "datacenter-azure-core-"* | \
@@ -709,9 +715,10 @@ getEditionRank() {
"essentials" | "essentials-"* ) echo 5 ;; "essentials" | "essentials-"* ) echo 5 ;;
"hv" | "hv-"* ) echo 10 ;; "hv" | "hv-"* ) echo 10 ;;
* ) echo 99 ;; * ) echo 99 ;;
esac esac ;;
;;
* ) * )
case "$edition" in case "$edition" in
"enterprise-iot" | "enterprise-iot-"* | "iot" | "iot-"* ) echo 3 ;; "enterprise-iot" | "enterprise-iot-"* | "iot" | "iot-"* ) echo 3 ;;
"enterprise-ltsc" | "enterprise-ltsc-"* | "ltsc" | "ltsc-"* ) echo 4 ;; "enterprise-ltsc" | "enterprise-ltsc-"* | "ltsc" | "ltsc-"* ) echo 4 ;;
@@ -723,8 +730,8 @@ getEditionRank() {
"home" | "home-"* ) echo 6 ;; "home" | "home-"* ) echo 6 ;;
"starter" | "starter-"* ) echo 7 ;; "starter" | "starter-"* ) echo 7 ;;
* ) echo 99 ;; * ) echo 99 ;;
esac esac ;;
;;
esac esac
return 0 return 0
@@ -735,6 +742,7 @@ getEditionPolicy() {
local base="${1,,}" local base="${1,,}"
case "$base" in case "$base" in
"win20"* ) "win20"* )
printf '%s\n' \ printf '%s\n' \
"normalizeServerEditionID" \ "normalizeServerEditionID" \
@@ -750,9 +758,10 @@ getEditionPolicy() {
"-datacenter-azure-core" \ "-datacenter-azure-core" \
"-enterprise-core" \ "-enterprise-core" \
"-web-core" \ "-web-core" \
"-hv" "-hv" ;;
;;
* ) * )
printf '%s\n' \ printf '%s\n' \
"normalizeEditionID" \ "normalizeEditionID" \
"-enterprise" \ "-enterprise" \
@@ -764,8 +773,8 @@ getEditionPolicy() {
"-home" \ "-home" \
"-home-premium" \ "-home-premium" \
"-home-basic" \ "-home-basic" \
"-starter" "-starter" ;;
;;
esac esac
return 0 return 0
@@ -774,18 +783,20 @@ getEditionPolicy() {
normalizeEdition() { normalizeEdition() {
local source="${1,,}" local source="${1,,}"
local edition transliterated
local edition
source="${source//evaluation/}" source="${source//evaluation/}"
source=$(printf '%s' "$source" |
uconv -x 'Any-Latin; Latin-ASCII' 2>/dev/null) || return 1 if transliterated=$(printf '%s' "$source" |
uconv -x 'Any-Latin; Latin-ASCII' 2>/dev/null); then
source="$transliterated"
fi
edition=$(sed -E \ edition=$(sed -E \
-e 's/[^a-z0-9]+/-/g' \ -e 's/[^a-z0-9]+/-/g' \
-e 's/^-+//' \ -e 's/^-+//' \
-e 's/-+$//' \ -e 's/-+$//' \
<<< "$source") <<< "$source") || edition=""
echo "$edition" echo "$edition"
return 0 return 0
@@ -799,11 +810,15 @@ normalizeEditionID() {
edition=$(normalizeEdition "$1") || return 1 edition=$(normalizeEdition "$1") || return 1
case "$edition" in case "$edition" in
"pro" | "professional" | "business" ) "pro" | "professional" | "business" )
edition="" ;; edition="" ;;
"pro-n" | "pron" | "professional-n" | "professionaln" | "business-n" | "businessn" ) "pro-n" | "pron" | "professional-n" | "professionaln" | "business-n" | "businessn" )
edition="n" ;; edition="n" ;;
* ) * )
if ! isClientEdition "$edition"; then if ! isClientEdition "$edition"; then
case "$edition" in case "$edition" in
*"-n" ) base="${edition%-n}" ;; *"-n" ) base="${edition%-n}" ;;
@@ -816,10 +831,13 @@ normalizeEditionID() {
fi fi
fi ;; fi ;;
esac esac
case "${id,,}" in case "${id,,}" in
"win10"* | "win11"* ) "win10"* | "win11"* )
case "$edition" in case "$edition" in
"iot-enterprise-ltsc" | \ "iot-enterprise-ltsc" | \
"iot-enterprise-ltsc-"[0-9][0-9][0-9][0-9] ) "iot-enterprise-ltsc-"[0-9][0-9][0-9][0-9] )
@@ -827,8 +845,8 @@ normalizeEditionID() {
"enterprise-ltsc" | \ "enterprise-ltsc" | \
"enterprise-ltsc-"[0-9][0-9][0-9][0-9] ) "enterprise-ltsc-"[0-9][0-9][0-9][0-9] )
edition="ltsc" ;; edition="ltsc" ;;
esac esac ;;
;;
esac esac
echo "$edition" echo "$edition"
+86 -25
View File
@@ -273,13 +273,17 @@ detectLanguage() {
for path in "${paths[@]}"; do for path in "${paths[@]}"; do
lang=$(xmlstarlet sel -T -t -v "normalize-space(string(($path)[1]))" - 2>/dev/null <<< "$xml") || lang="" if ! lang=$(xmlstarlet sel -T -t -v "normalize-space(string(($path)[1]))" - 2>/dev/null <<< "$xml"); then
warn "failed to read language metadata from Windows image!"
return 0
fi
[ -n "$lang" ] && break [ -n "$lang" ] && break
done done
if [ -z "$lang" ]; then if [ -z "$lang" ]; then
warn "Language could not be detected from ISO!" warn "language could not be detected from ISO!"
return 0 return 0
fi fi
@@ -290,7 +294,7 @@ detectLanguage() {
return 0 return 0
fi fi
warn "Invalid language detected: \"$lang\"" warn "invalid language detected: \"$lang\""
return 0 return 0
} }
@@ -617,7 +621,7 @@ detectLegacy() {
if [ -n "$marker" ]; then if [ -n "$marker" ]; then
error "Windows IA-64 (Itanium) images are not supported by this container!" error "Windows IA-64 (Itanium) images are not supported by this container!"
exit 67 return 2
fi fi
marker=$(find "$dir" -maxdepth 1 -type d -iname WIN95 -print -quit) || return 2 marker=$(find "$dir" -maxdepth 1 -type d -iname WIN95 -print -quit) || return 2
@@ -786,7 +790,6 @@ readWimHeader() {
if ! rm -f -- "$header"; then if ! rm -f -- "$header"; then
enabled "$DEBUG" && echo "Failed to remove the previous temporary WIM header: $header" >&2 enabled "$DEBUG" && echo "Failed to remove the previous temporary WIM header: $header" >&2
error "Failed to prepare Windows image header!"
return 1 return 1
fi fi
@@ -794,35 +797,30 @@ readWimHeader() {
# extracting install.wim or install.esd from the ISO. # extracting install.wim or install.esd from the ISO.
if ! udfread range --ignore-case -o "$header" "$iso" "$image" 0 208 >/dev/null 2>&1; then if ! udfread range --ignore-case -o "$header" "$iso" "$image" 0 208 >/dev/null 2>&1; then
enabled "$DEBUG" && echo "udfread failed to read the first 208 bytes of $image from $iso." >&2 enabled "$DEBUG" && echo "udfread failed to read the first 208 bytes of $image from $iso." >&2
error "Failed to read Windows image header!"
rm -f -- "$header" rm -f -- "$header"
return 1 return 1
fi fi
if ! size=$(stat -c%s -- "$header"); then if ! size=$(stat -c%s -- "$header"); then
enabled "$DEBUG" && echo "Failed to determine the size of the temporary WIM header: $header" >&2 enabled "$DEBUG" && echo "Failed to determine the size of the temporary WIM header: $header" >&2
error "Failed to read Windows image header!"
rm -f -- "$header" rm -f -- "$header"
return 1 return 1
fi fi
if (( size != 208 )); then if (( size != 208 )); then
enabled "$DEBUG" && echo "The WIM header is $size bytes instead of the expected 208 bytes." >&2 enabled "$DEBUG" && echo "The WIM header is $size bytes instead of the expected 208 bytes." >&2
error "Failed to read Windows image header!"
rm -f -- "$header" rm -f -- "$header"
return 1 return 1
fi fi
if ! signature=$(od -An -N8 -tx1 "$header" | tr -d ' \n'); then if ! signature=$(od -An -N8 -tx1 "$header" | tr -d ' \n'); then
enabled "$DEBUG" && echo "Failed to read the WIM header signature from $header." >&2 enabled "$DEBUG" && echo "Failed to read the WIM header signature from $header." >&2
error "Failed to read Windows image header!"
rm -f -- "$header" rm -f -- "$header"
return 1 return 1
fi fi
if [[ "$signature" != "4d5357494d000000" ]]; then if [[ "$signature" != "4d5357494d000000" ]]; then
enabled "$DEBUG" && echo "The WIM header has an invalid signature: ${signature:-empty}." >&2 enabled "$DEBUG" && echo "The WIM header has an invalid signature: ${signature:-empty}." >&2
error "Failed to read Windows image header!"
rm -f -- "$header" rm -f -- "$header"
return 1 return 1
fi fi
@@ -1241,7 +1239,7 @@ configureImage() {
if [[ "$DETECTED" == "win81x86"* || "$DETECTED" == "win10x86"* ]]; then if [[ "$DETECTED" == "win81x86"* || "$DETECTED" == "win10x86"* ]]; then
error "The 32-bit version of $desc is not supported!" error "The 32-bit version of $desc is not supported!"
exit 67 return 2
fi fi
local msg="the answer file for $desc was not found ($DETECTED.xml)" local msg="the answer file for $desc was not found ($DETECTED.xml)"
@@ -1269,18 +1267,14 @@ configureImage() {
detectImageInfo() { detectImageInfo() {
local image_info="$1" local image_info="$1"
local desc index rc local desc index rc
checkPlatform "$image_info" || { checkPlatform "$image_info" || return 2
enabled "$DEBUG" && echo "Platform validation failed for the Windows image metadata." >&2
exit 67
}
local output local output
output=$(detectVersion "$image_info") || { output=$(detectVersion "$image_info") || {
enabled "$DEBUG" && echo "Version detection failed while parsing the Windows image metadata." >&2 enabled "$DEBUG" && echo "Version detection failed while parsing the Windows image metadata." >&2
error "Failed to detect Windows version from image metadata!" error "Failed to detect the Windows version from image metadata!"
return 1 return 1
} }
@@ -1292,16 +1286,18 @@ detectImageInfo() {
validateEdition || { validateEdition || {
enabled "$DEBUG" && echo "Edition validation failed for detected image: ${DETECTED:-empty}, index: ${index:-empty}." >&2 enabled "$DEBUG" && echo "Edition validation failed for detected image: ${DETECTED:-empty}, index: ${index:-empty}." >&2
error "Failed to validate Windows edition from image metadata!" error "Failed to validate the Windows edition from image metadata!"
return 1 return 1
} }
if [ -z "$DETECTED" ]; then if [ -z "$DETECTED" ]; then
unknownImage || { unknownImage || {
rc=$? rc=$?
enabled "$DEBUG" && echo "Unknown-image handling failed after no Windows version could be detected (status $rc)." >&2 enabled "$DEBUG" && echo "Unknown-image handling failed after no Windows version could be detected (status $rc)." >&2
return "$rc" return "$rc"
} }
return 0 return 0
fi fi
@@ -1337,25 +1333,84 @@ detectIsoImage() {
# the caller may extract the media. Metadata parsing/configuration errors use 2. # the caller may extract the media. Metadata parsing/configuration errors use 2.
image=$(findIsoImage "$iso") || { image=$(findIsoImage "$iso") || {
rc=$? rc=$?
enabled "$DEBUG" && echo "Direct ISO image lookup stopped with status $rc." >&2 enabled "$DEBUG" && echo "ISO image lookup failed (status $rc)." >&2
return "$rc" return "$rc"
} }
header=$(readWimHeader "$iso" "$image") || { header=$(readWimHeader "$iso" "$image") || {
enabled "$DEBUG" && echo "Reading the WIM header failed for $image." >&2 error "Failed to read the Windows image header!"
return 2 return 2
} }
image_info=$(readIsoImageInfo "$iso" "$image" "$header") || { image_info=$(readIsoImageInfo "$iso" "$image" "$header") || {
enabled "$DEBUG" && echo "Reading the WIM XML metadata failed for $image." >&2 error "Failed to read the Windows image metadata!"
error "Failed to read Windows image metadata!"
return 2 return 2
} }
info "Detecting version from ISO image..." info "Detecting version from ISO image..."
detectImageInfo "$image_info" || { detectImageInfo "$image_info" || {
enabled "$DEBUG" && echo "Processing the Windows image metadata failed." >&2 error "Failed to process the Windows image metadata!"
return 2
}
return 0
}
detectESDImage() {
local iso="$1"
local image_info install_info output index rc
local -a detected=()
image_info=$(wimlib-imagex info "$iso" --xml 2>/dev/null |
iconv -f UTF-16LE -t UTF-8 2>/dev/null) || {
rc=$?
error "Cannot read ESD file information (status $rc)."
return 2
}
# Microsoft download ESDs use images 1-3 for setup media, WinPE, and Windows
# Setup; images 4 and higher contain installable editions.
if ! install_info=$(xmlstarlet ed \
-d '/WIM/IMAGE[number(@INDEX) < 4]' \
<<< "$image_info" 2>/dev/null); then
error "Cannot read installable images from ESD file!"
return 2
fi
checkPlatform "$install_info" || return 2
local output
output=$(detectVersion "$install_info") || {
error "Failed to detect Windows version from the ESD metadata!"
return 2
}
mapfile -t detected <<< "$output"
index="${detected[1]:-}"
if [ -z "$index" ]; then
error "Failed to select an installation image based on the ESD metadata!"
return 2
fi
# extractESD removes every other image, leaving the selected edition at
# index 1. Detect against that final layout so the generated answer file
# already references the index that will exist after extraction.
if ! image_info=$(xmlstarlet ed \
-d "/WIM/IMAGE[number(@INDEX) != $index]" \
-u "/WIM/IMAGE[@INDEX='$index']/@INDEX" -v '1' \
<<< "$install_info" 2>/dev/null); then
error "Cannot prepare ESD image information!"
return 2
fi
info "Detecting version from ESD image..."
detectImageInfo "$image_info" || {
error "Failed to process the ESD image metadata!"
return 2 return 2
} }
@@ -1364,6 +1419,8 @@ detectIsoImage() {
baseDir() { baseDir() {
# TODO: Can be removed with base image 7.45+
local path="${1%/}" local path="${1%/}"
[[ -z "$path" || "$path" == "/" ]] && { [[ -z "$path" || "$path" == "/" ]] && {
@@ -1584,7 +1641,7 @@ extractESD() {
return 1 return 1
fi fi
checkPlatform "$xml" || return checkPlatform "$installXml" || return
output=$(detectVersion "$installXml") || return output=$(detectVersion "$installXml") || return
mapfile -t detected <<< "$output" mapfile -t detected <<< "$output"
@@ -1990,7 +2047,11 @@ buildImage() {
base=$(basename "$BOOT") base=$(basename "$BOOT")
local out="$TMP/${base%.*}.tmp" local out="$TMP/${base%.*}.tmp"
rm -f "$out"
if ! rm -f "$out"; then
error "Failed to remove temporary ISO image: $out"
return 1
fi
desc=$(printVariant "$DETECTED" "ISO") desc=$(printVariant "$DETECTED" "ISO")
+171 -48
View File
@@ -3,20 +3,43 @@ set -Eeuo pipefail
startWindows() { startWindows() {
parseVersion || exit 58 parseVersion || {
parseLanguage || exit 62 error "Failed to parse the Windows version!"
detectCustom || exit 64 exit 58
}
parseLanguage || {
error "Failed to parse the Windows language!"
exit 62
}
detectCustom || {
error "Failed to scan for custom installation media!"
exit 64
}
local rc=0
startInstall || rc=$?
(( rc > 1 )) && exit "$rc"
if (( rc )); then
bootWindows || {
error "Failed to boot Windows!"
exit 66
}
if ! startInstall; then
bootWindows || exit 66
return 0 return 0
fi fi
if ! hasImage "$ISO"; then if ! hasImage "$ISO"; then
if ! downloadImage "$ISO" "$VERSION" "$LANGUAGE"; then if ! downloadImage "$ISO" "$VERSION" "$LANGUAGE"; then
removeImage "$ISO" || : removeImage "$ISO" || :
exit 68 exit 68
fi fi
fi fi
local boot="$BOOT" local boot="$BOOT"
@@ -48,11 +71,12 @@ selectWindowsImage() {
XML="" XML=""
FB="falling back to manual installation!" FB="falling back to manual installation!"
normalizeDetected || return 70 normalizeDetected || :
if [ -n "$DETECTED" ]; then if [ -n "$DETECTED" ]; then
if ! setImage; then if ! setImage; then
error "Failed to configure the detected Windows image!"
return 70 return 70
fi fi
@@ -61,6 +85,7 @@ selectWindowsImage() {
fi fi
if ! extractImage "$iso" "$dir" "$VERSION"; then if ! extractImage "$iso" "$dir" "$VERSION"; then
error "Failed to extract the Windows installation image!"
removeImage "$iso" || : removeImage "$iso" || :
return 72 return 72
fi fi
@@ -76,11 +101,21 @@ selectWindowsImage() {
detectIsoImage "$iso" && return 0 detectIsoImage "$iso" && return 0
rc=$? rc=$?
(( rc == 1 )) || return 76 if (( rc != 1 )); then
error "Failed to inspect the Windows installation ISO!"
return 76
fi
elif [[ "${iso,,}" == *.esd ]]; then
detectESDImage "$iso" && return 0
error "Failed to inspect the Windows installation ESD!"
return 76
fi fi
if ! extractImage "$iso" "$dir" "$VERSION"; then if ! extractImage "$iso" "$dir" "$VERSION"; then
error "Failed to extract the Windows installation image!"
removeImage "$iso" || : removeImage "$iso" || :
return 74 return 74
fi fi
@@ -90,9 +125,15 @@ selectWindowsImage() {
detectImage "$dir" && return 0 detectImage "$dir" && return 0
rc=$? rc=$?
(( rc == 1 )) || return 76 if (( rc != 1 )); then
error "Failed to detect the extracted Windows installation image!"
return 76
fi
skipUnattended "$dir" "$iso" "$boot" || return 76 skipUnattended "$dir" "$iso" "$boot" || {
error "Failed to fall back to manual installation!"
return 76
}
handled=1 handled=1
return 0 return 0
@@ -108,24 +149,37 @@ configureMachine() {
desc=$(printVariant "$DETECTED" "$DETECTED") || return 78 desc=$(printVariant "$DETECTED" "$DETECTED") || return 78
if ! checkMemory "$DETECTED"; then if ! checkMemory "$DETECTED"; then
if [ -z "$CUSTOM" ]; then if [ -z "$CUSTOM" ]; then
useOriginalImage "$iso" || return 79 useOriginalImage "$iso" || {
error "Failed to preserve the original installation image!"
return 79
}
fi fi
return 79 return 79
fi fi
if ! setMachine "$DETECTED" "$iso" "$dir" "$desc"; then if ! setMachine "$DETECTED" "$iso" "$dir" "$desc"; then
error "Failed to configure the virtual machine for $desc!"
return 80 return 80
fi fi
if ! restoreMachineState; then if ! restoreMachineState; then
error "Failed to restore the saved machine state!"
return 82 return 82
fi fi
if ! supportsUnattended "$DETECTED"; then if ! supportsUnattended "$DETECTED"; then
skipUnattended "$dir" "$iso" "$boot" "N" || return 83
skipUnattended "$dir" "$iso" "$boot" "N" || {
error "Failed to fall back to manual installation!"
return 83
}
handled=1 handled=1
return 0 return 0
fi fi
return 0 return 0
@@ -141,16 +195,23 @@ prepareWindowsImage() {
if supportsXML "$DETECTED"; then if supportsXML "$DETECTED"; then
if ! createOverlay "$XML" "$LANGUAGE" "$TMP/setup"; then if ! createOverlay "$XML" "$LANGUAGE" "$TMP/setup"; then
error "Failed to create the Windows setup overlay!"
return 84 return 84
fi fi
if ! createSetupImage "$TMP/setup" "$STORAGE/setup.img"; then if ! createSetupImage "$TMP/setup" "$STORAGE/setup.img"; then
error "Failed to create the Windows setup image!"
return 86 return 86
fi fi
# Bootable ISOs can be reused unchanged with the generated setup image. # Bootable ISOs can be reused unchanged with the generated setup image.
if (( ! extracted )); then if (( ! extracted )) && isDirectImage "$iso"; then
useOriginalImage "$iso" || return 88
useOriginalImage "$iso" || {
error "Failed to preserve the original installation image!"
return 88
}
return 0 return 0
fi fi
@@ -158,28 +219,54 @@ prepareWindowsImage() {
# Extracted modern sources and SIF-based legacy media require a clean rebuild. # Extracted modern sources and SIF-based legacy media require a clean rebuild.
if (( ! extracted )); then if (( ! extracted )); then
if ! extractImage "$iso" "$dir" "$VERSION"; then if ! extractImage "$iso" "$dir" "$VERSION"; then
error "Failed to extract the Windows installation image!"
removeImage "$iso" || : removeImage "$iso" || :
return 90 return 90
fi fi
fi fi
if ! prepareImage "$iso" "$dir"; then if ! prepareImage "$iso" "$dir"; then
error "Failed to prepare the Windows installation image!"
return 92 return 92
fi fi
removeImage "$iso" || return 96 removeImage "$iso" || {
buildImage "$dir" || return 98 error "Failed to remove the source installation image!"
return 96
}
buildImage "$dir" || {
error "Failed to build the Windows installation image!"
return 98
}
return 0 return 0
} }
bootWindows() { bootWindows() {
restoreMachineState || return if ! restoreMachineState; then
restoreBootMode || return error "Failed to restore the saved machine state!"
restoreMachine || return return 1
reserveSambaPorts || return fi
if ! restoreBootMode; then
error "Failed to restore the saved boot mode!"
return 1
fi
if ! restoreMachine; then
error "Failed to restore the saved machine type!"
return 1
fi
if ! reserveSambaPorts; then
error "Failed to reserve Samba ports!"
return 1
fi
return 0 return 0
} }
@@ -211,13 +298,17 @@ startInstall() {
case "${boot,,}" in case "${boot,,}" in
"windows."* ) "windows."* )
error "The download filename \"$file\" uses the reserved \"windows.*\" namespace!" error "The download filename \"$file\" uses the reserved \"windows.*\" namespace!"
exit 58 ;; return 58 ;;
esac esac
else else
local language local language
language=$(getLanguage "$LANGUAGE" "culture") if ! language=$(getLanguage "$LANGUAGE" "culture"); then
error "Failed to determine the Windows language!"
return 62
fi
language="${language%%-*}" language="${language%%-*}"
if [ -n "$language" ] && [[ "${language,,}" != "en" ]]; then if [ -n "$language" ] && [[ "${language,,}" != "en" ]]; then
@@ -235,28 +326,32 @@ startInstall() {
if ! rm -rf -- "$TMP"; then if ! rm -rf -- "$TMP"; then
error "Failed to remove directory \"$TMP\" !" error "Failed to remove directory \"$TMP\" !"
exit 50 return 50
fi fi
local setup="$STORAGE/setup.img" local setup="$STORAGE/setup.img"
if ! rm -f -- "$setup" "${setup}.tmp"; then if ! rm -f -- "$setup" "${setup}.tmp"; then
error "Failed to remove setup image \"$setup\" !" error "Failed to remove setup image \"$setup\" !"
exit 50 return 50
fi fi
local previousBase local previousBase
if ! previousBase=$(readState "base"); then if ! previousBase=$(readState "base"); then
error "Failed to read the previous installation state!" error "Failed to read the previous installation state!"
exit 50 return 50
fi fi
skipInstall "$BOOT" "$previousBase" && return 1 local rc=0
skipInstall "$BOOT" "$previousBase" || rc=$?
(( rc > 1 )) && return "$rc"
(( rc )) || return 1
if [ -z "$previousBase" ] && hasData; then if [ -z "$previousBase" ] && hasData; then
if enabled "$SHUTDOWN" && [ ! -f "$STORAGE/windows.boot" ]; then if enabled "$SHUTDOWN" && [ ! -f "$STORAGE/windows.boot" ]; then
discardPrevious "" || exit 50 discardPrevious "" || return 50
else else
if ! backupPrevious ""; then if ! backupPrevious ""; then
warn "the backup was incomplete, continuing with installation..." warn "the backup was incomplete, continuing with installation..."
@@ -267,7 +362,7 @@ startInstall() {
if ! makeDir "$TMP"; then if ! makeDir "$TMP"; then
error "Failed to create directory \"$TMP\" !" error "Failed to create directory \"$TMP\" !"
exit 50 return 50
fi fi
if [ -z "$CUSTOM" ]; then if [ -z "$CUSTOM" ]; then
@@ -285,27 +380,27 @@ startInstall() {
if [ -n "$CUSTOM" ] || [ ! -s "$BOOT" ]; then if [ -n "$CUSTOM" ] || [ ! -s "$BOOT" ]; then
if ! rm -f -- "$BOOT"; then if ! rm -f -- "$BOOT"; then
error "Failed to remove obsolete ISO file \"$BOOT\" !" error "Failed to remove obsolete ISO file \"$BOOT\" !"
exit 50 return 50
fi fi
fi fi
if ! find "$STORAGE" -maxdepth 1 -type f -iname 'data.*' -not -iname '*.iso' -delete; then if ! find "$STORAGE" -maxdepth 1 -type f -iname 'data.*' -not -iname '*.iso' -delete; then
error "Failed to remove obsolete disk files from \"$STORAGE\" !" error "Failed to remove obsolete disk files from \"$STORAGE\" !"
exit 50 return 50
fi fi
if ! find "$STORAGE" -maxdepth 1 -type f -iname 'windows.*' -not -iname '*.iso' -delete; then if ! find "$STORAGE" -maxdepth 1 -type f -iname 'windows.*' -not -iname '*.iso' -delete; then
error "Failed to remove obsolete Windows files from \"$STORAGE\" !" error "Failed to remove obsolete Windows files from \"$STORAGE\" !"
exit 50 return 50
fi fi
if ! find "$STORAGE" -maxdepth 1 -type f \( -iname '*.rom' -or -iname '*.vars' \) -delete; then if ! find "$STORAGE" -maxdepth 1 -type f \( -iname '*.rom' -or -iname '*.vars' \) -delete; then
error "Failed to remove obsolete firmware files from \"$STORAGE\" !" error "Failed to remove obsolete firmware files from \"$STORAGE\" !"
exit 50 return 50
fi fi
if [ -z "$CUSTOM" ] && [[ "${VERSION,,}" != "http"* ]]; then if [ -z "$CUSTOM" ] && [[ "${VERSION,,}" != "http"* ]]; then
checkMemory "$VERSION" || exit 67 checkMemory "$VERSION" || return 67
fi fi
# Work from the temporary directory so the persistent source path can # Work from the temporary directory so the persistent source path can
@@ -313,7 +408,7 @@ startInstall() {
if [ -z "$CUSTOM" ] && [ -f "$BOOT" ] && [ -s "$BOOT" ]; then if [ -z "$CUSTOM" ] && [ -f "$BOOT" ] && [ -s "$BOOT" ]; then
if ! mv -f -- "$BOOT" "$ISO"; then if ! mv -f -- "$BOOT" "$ISO"; then
error "Failed to move ISO file from \"$BOOT\" to \"$ISO\" !" error "Failed to move ISO file from \"$BOOT\" to \"$ISO\" !"
exit 50 return 50
fi fi
fi fi
@@ -333,7 +428,7 @@ skipUnattended() {
# so they cannot use the manual-install fallback. # so they cannot use the manual-install fallback.
if ! isDirectImage "$iso"; then if ! isDirectImage "$iso"; then
error "Failed to boot \"$iso\" because it is not a directly bootable ISO image!" error "Failed to boot \"$iso\" because it is not a directly bootable ISO image!"
exit 60 return 1
fi fi
# When automatic preparation fails, inspect extracted media to determine # When automatic preparation fails, inspect extracted media to determine
@@ -382,7 +477,7 @@ skipInstall() {
if ! writeState "base" "$previousBase"; then if ! writeState "base" "$previousBase"; then
error "Failed to migrate the previous installation state!" error "Failed to migrate the previous installation state!"
exit 50 return 50
fi fi
fi fi
@@ -390,10 +485,12 @@ skipInstall() {
# Older releases may have left a rebuilt custom ISO at its synthetic source # Older releases may have left a rebuilt custom ISO at its synthetic source
# identity. A completed installation no longer needs that installation media. # identity. A completed installation no longer needs that installation media.
if [[ "${previousBase,,}" == "windows."* ]] && hasData && [ -f "$marker" ]; then if [[ "${previousBase,,}" == "windows."* ]] && hasData && [ -f "$marker" ]; then
if ! rm -f -- "$STORAGE/$previousBase"; then if ! rm -f -- "$STORAGE/$previousBase"; then
error "Failed to remove obsolete ISO file \"$STORAGE/$previousBase\" !" error "Failed to remove obsolete ISO file \"$STORAGE/$previousBase\" !"
exit 50 return 50
fi fi
fi fi
# A changed source invalidates an unfinished installation. Back up an # A changed source invalidates an unfinished installation. Back up an
@@ -404,7 +501,7 @@ skipInstall() {
if ! rm -f -- "$STORAGE/$previousBase"; then if ! rm -f -- "$STORAGE/$previousBase"; then
error "Failed to remove ISO file \"$STORAGE/$previousBase\" !" error "Failed to remove ISO file \"$STORAGE/$previousBase\" !"
exit 50 return 50
fi fi
return 1 return 1
@@ -430,7 +527,7 @@ skipInstall() {
fi fi
if enabled "$SHUTDOWN" && [ ! -f "$marker" ]; then if enabled "$SHUTDOWN" && [ ! -f "$marker" ]; then
discardPrevious "$STORAGE/$previousBase" || exit 50 discardPrevious "$STORAGE/$previousBase" || return 50
return 1 return 1
fi fi
@@ -469,7 +566,10 @@ finishInstall() {
fi fi
local file="$STORAGE/windows.ver" local file="$STORAGE/windows.ver"
cp -f /etc/version "$file" || return 1 cp -f /etc/version "$file" || {
error "Failed to save the Windows installation version!"
return 1
}
if ! setOwner "$file"; then if ! setOwner "$file"; then
warn "Failed to set the owner for \"$file\" !" warn "Failed to set the owner for \"$file\" !"
@@ -477,15 +577,23 @@ finishInstall() {
if [[ "$boot" == "$STORAGE/"* ]]; then if [[ "$boot" == "$STORAGE/"* ]]; then
if [[ "$aborted" != [Yy1]* ]] || [ -z "$CUSTOM" ]; then if [[ "$aborted" != [Yy1]* ]] || [ -z "$CUSTOM" ]; then
base=$(basename "$boot") base=$(basename "$boot")
writeState "base" "$base" || return 1 writeState "base" "$base" || {
error "Failed to save the Windows installation source!"
return 1
}
fi fi
fi fi
if [[ "${PLATFORM,,}" == "x64" ]]; then if [[ "${PLATFORM,,}" == "x64" ]]; then
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
writeState "mode" "$BOOT_MODE" || return 1 writeState "mode" "$BOOT_MODE" || {
error "Failed to save the Windows boot mode!"
return 1
}
else else
@@ -496,14 +604,22 @@ finishInstall() {
fi fi
if (( secure )); then if (( secure )); then
BOOT_MODE="windows_secure" BOOT_MODE="windows_secure"
writeState "mode" "$BOOT_MODE" || return 1 writeState "mode" "$BOOT_MODE" || {
error "Failed to save the Windows boot mode!"
return 1
}
fi fi
fi fi
fi fi
reserveSambaPorts || return 1 reserveSambaPorts || {
error "Failed to reserve Samba ports!"
return 1
}
if ! rm -rf -- "$TMP"; then if ! rm -rf -- "$TMP"; then
error "Failed to remove directory \"$TMP\" !" error "Failed to remove directory \"$TMP\" !"
@@ -516,7 +632,6 @@ finishInstall() {
findFile() { findFile() {
local fname="$1" local fname="$1"
local dir file base local dir file base
local boot="$STORAGE/windows.boot" local boot="$STORAGE/windows.boot"
@@ -896,7 +1011,12 @@ detectImage() {
local image_info local image_info
image_info=$(readImageInfo "$wim") || return $? image_info=$(readImageInfo "$wim") || return $?
detectImageInfo "$image_info" || return 2 detectImageInfo "$image_info" || {
error "Failed to process the Windows image metadata!"
return 2
}
return 0
} }
prepareImage() { prepareImage() {
@@ -1212,7 +1332,10 @@ createOverlay() {
return 1 return 1
fi fi
addAnswerFile "$asset" "$language" "$stage" || return 1 addAnswerFile "$asset" "$language" "$stage" || {
error "Failed to include the Windows answer file!"
return 1
}
return 0 return 0
} }
@@ -1309,8 +1432,8 @@ backupPrevious () {
failed="Y" failed="Y"
fi fi
[ -z "$(ls -A "$dir")" ] && rm -rf "$dir" rmdir "$dir" 2>/dev/null || :
[ -z "$(ls -A "$root")" ] && rm -rf "$root" rmdir "$root" 2>/dev/null || :
[ -n "$failed" ] && return 1 [ -n "$failed" ] && return 1
+19 -10
View File
@@ -175,13 +175,16 @@ downloadWindowsLink() {
--max-filesize 100K \ --max-filesize 100K \
-- "$skuUrl") || return -- "$skuUrl") || return
# Let jq parsing failures propagate so malformed API data is not mistaken skuId=$(printf '%s\n' "$skuJson" | jq --arg LANG "$language" -r 'first(.Skus[]? | select(.Language == $LANG) | .Id) // empty') 2>/dev/null || skuId=""
# for a normal missing-result response. The same applies to the link data.
skuId=$(printf '%s\n' "$skuJson" | jq --arg LANG "$language" -r 'first(.Skus[]? | select(.Language == $LANG) | .Id) // empty') 2>/dev/null || return
if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]]; then if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]]; then
language=$(getLanguage "$lang" "desc") if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then
error "No download in the $language language available for $desc!" language=$(getLanguage "$lang" "desc")
error "No download in the $language language available for $desc!"
else
error "Microsoft server provided us no SKU ID in response to our request!"
info "Response: $skuJson"
fi
return 1 return 1
fi fi
@@ -214,10 +217,10 @@ downloadWindowsLink() {
return 1 return 1
fi fi
link=$(printf '%s\n' "$linkJson" | jq --argjson TYPE "$type" -r 'first(.ProductDownloadOptions[]? | select(.DownloadType == $TYPE) | .Uri) // empty') 2>/dev/null || return link=$(printf '%s\n' "$linkJson" | jq --argjson TYPE "$type" -r 'first(.ProductDownloadOptions[]? | select(.DownloadType == $TYPE) | .Uri) // empty') 2>/dev/null || link=""
if [ -z "$link" ] || [[ "${link,,}" == "null" ]]; then if [ -z "$link" ] || [[ "${link,,}" == "null" ]]; then
error "Microsoft server gave us no download link to our request for an automated download!" error "Microsoft server provided us no download link to our request for an automated download!"
info "Response: $linkJson" info "Response: $linkJson"
return 1 return 1
fi fi
@@ -287,7 +290,7 @@ downloadWindows() {
grep -Eio "<option[^>]*value=[\"'][0-9]+[\"'][^>]*>[[:space:]]*Windows[^<]*" | grep -Eio "<option[^>]*value=[\"'][0-9]+[\"'][^>]*>[[:space:]]*Windows[^<]*" |
sed -nE "s/.*value=[\"']([0-9]+)[\"'].*/\1/p" | sed -nE "s/.*value=[\"']([0-9]+)[\"'].*/\1/p" |
sed -n '1p' | sed -n '1p' |
cut -c 1-16) || return cut -c 1-16) || productId=""
enabled "$DEBUG" && echo "$productId" enabled "$DEBUG" && echo "$productId"
if [ -z "$productId" ]; then if [ -z "$productId" ]; then
@@ -1119,7 +1122,7 @@ verifyFile() {
info "Successfully verified $type!" && return 0 info "Successfully verified $type!" && return 0
fi fi
error "The downloaded file has an unknown $algo checksum: $hash , as the expected value was: $check. Please report this at $SUPPORT/issues" warn "the downloaded file has an unknown $algo checksum: $hash , as the expected value was: $check. Please report this at $SUPPORT/issues"
return 1 return 1
} }
@@ -1280,7 +1283,11 @@ downloadImage() {
desc=$(fromFile "$base") desc=$(fromFile "$base")
web_desc="$desc" web_desc="$desc"
tryDownload "$iso" "$version" "" "" "$desc" "$seconds" "$web_desc" || return tryDownload "$iso" "$version" "" "" "$desc" "$seconds" "$web_desc" || {
rc=$?
error "Failed to download the Windows image from the specified URL!"
return "$rc"
}
return 0 return 0
fi fi
@@ -1450,6 +1457,8 @@ downloadImage() {
if [[ "$tried" == "n" ]]; then if [[ "$tried" == "n" ]]; then
error "No download method is available for $desc!" error "No download method is available for $desc!"
else
error "All download methods failed for $desc!"
fi fi
return 1 return 1