1
0
mirror of https://github.com/dockur/windows.git synced 2026-07-27 21:42:36 +07:00

Compare commits

...

45 Commits

Author SHA1 Message Date
Kroese bada80331d fix: Derive NT5 boot load size from extracted image (#1991) 2026-07-26 08:34:21 +02:00
Kroese c589e1be18 fix: Extract legacy boot images using virtual sectors (#1990) 2026-07-26 08:02:28 +02:00
Kroese 2ac9d71b32 fix: Fall back to default boot load size for NT5 media (#1989) 2026-07-26 07:22:27 +02:00
Kroese e7e637531e fix: Avoid pipefail when reading boot load size (#1988) 2026-07-26 07:07:03 +02:00
Kroese b90ded928b fix: Read boot image offset during legacy fallback (#1987) 2026-07-26 06:40:59 +02:00
Kroese 0d0dd7be87 fix: Read legacy boot load size before image preparation (#1986) 2026-07-26 06:32:26 +02:00
Kroese 5b080ac6c8 build: Update workflow (#1985) 2026-07-26 06:03:43 +02:00
Kroese 6df58b5dc7 fix: Preserve source boot load size for legacy ISOs (#1984) 2026-07-26 05:51:44 +02:00
Kroese 8929f7cdcd feat: Refactor Windows answer file handling (#1983) 2026-07-26 05:34:24 +02:00
Kroese aa6240ff99 fix: Add the compact identifiers for Windows N (#1981) 2026-07-26 03:32:58 +02:00
Kroese 3d3bab023d fix: Limit XP EPYC workaround to x86 (#1980) 2026-07-26 03:28:22 +02:00
Kroese 36d127d8cf fix: Handling of UTF-16 batch files (#1979) 2026-07-26 03:18:41 +02:00
Kroese 2b7d7bf902 fix: Respect REBUILD=N for legacy Windows media (#1978) 2026-07-26 02:55:50 +02:00
Kroese 30d9858c7d fix: Warn instead of failing on domain XML updates (#1977) 2026-07-26 02:41:29 +02:00
Kroese 09941ba0f6 docs: Environment variables (#1976) 2026-07-26 02:33:30 +02:00
Kroese 828bdb1b29 fix: Preserve Server Evaluation identity during image detection (#1975) 2026-07-26 02:01:31 +02:00
Kroese c64cf2313b build: Add Windows installation validation workflows (#1974) 2026-07-26 01:52:13 +02:00
Kroese f45575c13f build: Update dependabot config (#1973) 2026-07-26 01:12:41 +02:00
Kroese 11b300149f fix: Legacy boot image extraction and load size (#1972) 2026-07-26 00:30:51 +02:00
Kroese 605f31af72 fix: Legacy ISO boot load size (#1971) 2026-07-26 00:10:41 +02:00
Kroese 4e35ead612 feat: Added option to prevent rebuild of the image (#1970) 2026-07-26 00:02:17 +02:00
Kroese 0a3bff5a7d docs: Document new REBUILD option (#1969) 2026-07-25 23:54:21 +02:00
Kroese fdad5260cf fix: Verify if OEM directory exists for legacy Windows versions (#1968) 2026-07-25 23:18:38 +02:00
Kroese 0728b3e0a8 feat: Remove Nano11 image (#1967) 2026-07-25 21:56:37 +02:00
Kroese 184ab1c481 fix: Legacy username validation (#1966) 2026-07-25 21:30:26 +02:00
Kroese 4cf7dc005b feat: Refactor legacy installation code (#1965) 2026-07-25 21:16:18 +02:00
Kroese da7dd544b3 feat: Enable optional logging and syntax checking for install.bat (#1964) 2026-07-25 20:00:11 +02:00
Kroese 213245e5c9 feat: Hide VirtIO driver installation windows (#1963) 2026-07-25 16:46:15 +02:00
Kroese 240db47ae0 build: Add blinter package for batch file linting (#1962) 2026-07-25 15:20:00 +02:00
Kroese 2ee0ae2e28 fix: Invalid Samba NetBIOS hostname (#1961) 2026-07-25 14:58:10 +02:00
Kroese bc17fdfe74 feat: Improve machine checking (#1959) 2026-07-25 14:47:34 +02:00
Kroese 3d9ede8852 docs: Environment variables (#1960) 2026-07-25 14:43:35 +02:00
Kroese 66d51a23c6 build: Update QEMU base image to v7.40 (#1958) 2026-07-25 06:15:24 +02:00
Kroese 6bdfb06827 feat: Improve image and answer file handling (#1957) 2026-07-25 06:14:00 +02:00
Kroese ce1e7b877d feat: Improve architecture detection for download links (#1956) 2026-07-25 03:30:32 +02:00
Kroese d1b3364471 feat: Merge client and server edition selection (#1955) 2026-07-25 02:46:26 +02:00
Kroese 4b5eb2c882 fix: Preserve WIM indices during edition detection (#1954) 2026-07-25 00:29:50 +02:00
Kroese fe36fe3ab8 fix: Preserve IoT evaluation identity (#1953) 2026-07-24 21:09:07 +02:00
Kroese c64467596b fix: Use qemu32 for XP on AMD EPYC (#1952) 2026-07-24 20:18:48 +02:00
Kroese 28b5ee1f08 feat: Inline local variable declarations (#1951) 2026-07-24 20:05:12 +02:00
Kroese 173b67b2af feat: Update download links (#1950) 2026-07-24 19:13:10 +02:00
Kroese b692649a4f fix: Remove internal download test (#1949) 2026-07-24 18:57:30 +02:00
Kroese b721ba2320 fix: Check machine type before applying q35 flags (#1948) 2026-07-24 18:47:45 +02:00
Kroese 6bfe2ff106 feat: Consolidate language alias handling (#1947) 2026-07-24 18:46:46 +02:00
Kroese c739e41e7e feat: Improve Windows media detection and selection (#1946) 2026-07-24 16:52:14 +02:00
36 changed files with 3990 additions and 1441 deletions
+7
View File
@@ -1,4 +1,5 @@
version: 2
updates:
- package-ecosystem: docker
directory: /
@@ -6,9 +7,15 @@ updates:
interval: weekly
cooldown:
default-days: 7
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
ignore:
- dependency-name: "*"
update-types:
- version-update:semver-minor
- version-update:semver-patch
+680
View File
@@ -0,0 +1,680 @@
name: Installation
on:
workflow_call:
inputs:
name:
description: Display name for the Windows version
required: true
type: string
version:
description: VERSION value passed to the container
required: true
type: string
runner:
description: GitHub Actions runner
required: false
default: ubuntu-24.04
type: string
image:
description: Container image to test
required: false
default: ghcr.io/dockur/windows:latest
type: string
callback:
description: Guest script type
required: false
default: powershell
type: string
cpu:
description: CPU model exposed to Windows
required: false
default: host
type: string
expected_caption:
description: Text expected in the Windows caption
required: true
type: string
expected_edition:
description: Expected Windows EditionID
required: false
default: ""
type: string
minimum_build:
description: Minimum acceptable Windows build number
required: true
type: number
platform:
description: Expected Windows platform
required: true
type: string
permissions:
contents: read
jobs:
install:
name: ${{ inputs.name }}
runs-on: ${{ inputs.runner }}
timeout-minutes: 180
env:
CONTAINER: windows-test
IMAGE: ${{ inputs.image }}
steps:
- name: Check KVM
shell: bash
run: |
set -Eeuo pipefail
test -c /dev/kvm
- name: Free disk space
shell: bash
run: |
set -Eeuo pipefail
sudo rm -rf \
/usr/local/.ghcup \
/usr/local/lib/android \
/usr/local/lib/node_modules \
/usr/local/share/boost \
/usr/local/share/chromium \
/usr/local/share/powershell \
/usr/share/dotnet \
/usr/share/swift \
/opt/az \
/opt/ghc \
/opt/google \
/opt/hostedtoolcache \
/opt/microsoft \
/opt/pipx
sudo apt-get clean
sudo rm -rf \
/var/cache/apt/* \
/var/lib/apt/lists/*
docker system prune \
--all \
--force \
--volumes > /dev/null || true
available_kb="$(df --output=avail / | tail -1)"
available_gb="$((available_kb / 1024 / 1024))"
echo "Available disk space: ${available_gb} GB"
if (( available_gb < 40 )); then
echo "At least 40 GB of free space is required."
exit 1
fi
- name: Prepare installation test
id: test
shell: bash
env:
CALLBACK: ${{ inputs.callback }}
run: |
set -Eeuo pipefail
case "$CALLBACK" in
powershell | legacy)
;;
*)
echo "Unsupported guest script type: $CALLBACK"
exit 1
;;
esac
token="$(cat /proc/sys/kernel/random/uuid)"
mkdir -p \
"$RUNNER_TEMP/data" \
"$RUNNER_TEMP/oem" \
"$RUNNER_TEMP/storage"
printf '%s\n' "$token" > "$RUNNER_TEMP/data/readme.txt"
case "$CALLBACK" in
powershell)
cat > "$RUNNER_TEMP/oem/ready.ps1" <<'POWERSHELL'
param(
[Parameter(Mandatory = $true)]
[string]$Token
)
$ErrorActionPreference = "Stop"
$windows = Get-CimInstance Win32_OperatingSystem
$registry = Get-ItemProperty `
"HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
$platform = switch (
$env:PROCESSOR_ARCHITECTURE.ToUpperInvariant()
) {
"AMD64" {
"x64"
}
"ARM64" {
"arm64"
}
"X86" {
"x86"
}
default {
$env:PROCESSOR_ARCHITECTURE.ToLowerInvariant()
}
}
while ($true) {
try {
$share = (
Get-Content `
-LiteralPath "\\host.lan\Data\readme.txt" `
-Raw
).Trim()
$result = @{
token = $Token
caption = [string]$windows.Caption
edition = [string]$registry.EditionID
version = [string]$windows.Version
build = [string]$windows.BuildNumber
platform = $platform
share = $share
}
$json = $result | ConvertTo-Json -Compress
$temporary = "\\host.lan\Data\windows.tmp"
$destination = "\\host.lan\Data\windows.json"
$encoding = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText(
$temporary,
$json,
$encoding
)
Move-Item `
-LiteralPath $temporary `
-Destination $destination `
-Force
break
}
catch {
Start-Sleep -Seconds 10
}
}
POWERSHELL
cat > "$RUNNER_TEMP/oem/install.bat" <<EOF
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass ^
-File C:\OEM\ready.ps1 ^
-Token "$token"
EOF
;;
legacy)
cat > "$RUNNER_TEMP/oem/ready.vbs" <<'VBSCRIPT'
Option Explicit
Const ForReading = 1
Const ForWriting = 2
Dim arguments
Dim token
Set arguments = WScript.Arguments
If arguments.Count < 1 Then
WScript.Quit 1
End If
token = arguments(0)
Function EscapeJson(value)
Dim result
result = CStr(value)
result = Replace(result, "\", "\\")
result = Replace(result, Chr(34), "\" & Chr(34))
result = Replace(result, vbCr, "\r")
result = Replace(result, vbLf, "\n")
result = Replace(result, vbTab, "\t")
EscapeJson = result
End Function
Function ReadRegistry(shell, path)
Dim value
value = ""
On Error Resume Next
value = shell.RegRead(path)
If Err.Number <> 0 Then
Err.Clear
value = ""
End If
On Error GoTo 0
ReadRegistry = CStr(value)
End Function
Function ReadTextFile(filesystem, path)
Dim file
Dim value
value = ""
Set file = filesystem.OpenTextFile(path, ForReading, False)
value = file.ReadAll
file.Close
value = Replace(value, vbCr, "")
value = Replace(value, vbLf, "")
ReadTextFile = value
End Function
Function GetPlatform(shell)
Dim architecture
architecture = UCase(shell.ExpandEnvironmentStrings("%PROCESSOR_ARCHITECTURE%"))
Select Case architecture
Case "AMD64"
GetPlatform = "x64"
Case "ARM64"
GetPlatform = "arm64"
Case "X86"
GetPlatform = "x86"
Case Else
GetPlatform = LCase(architecture)
End Select
End Function
Dim filesystem
Dim shell
Dim locator
Dim service
Dim systems
Dim system
Dim caption
Dim edition
Dim version
Dim build
Dim platform
Dim share
Dim json
Dim temporary
Dim destination
Dim file
Set filesystem = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
Set locator = CreateObject("WbemScripting.SWbemLocator")
Set service = locator.ConnectServer(".", "root\cimv2")
Set systems = service.ExecQuery("SELECT Caption, Version, BuildNumber FROM Win32_OperatingSystem")
caption = ""
version = ""
build = ""
For Each system In systems
caption = CStr(system.Caption)
version = CStr(system.Version)
build = CStr(system.BuildNumber)
Exit For
Next
edition = ReadRegistry(shell, "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EditionID")
platform = GetPlatform(shell)
temporary = "\\host.lan\Data\windows.tmp"
destination = "\\host.lan\Data\windows.json"
Do
On Error Resume Next
share = ReadTextFile(filesystem, "\\host.lan\Data\readme.txt")
If Err.Number = 0 Then
json = _
"{" & _
"""token"":""" & EscapeJson(token) & """," & _
"""caption"":""" & EscapeJson(caption) & """," & _
"""edition"":""" & EscapeJson(edition) & """," & _
"""version"":""" & EscapeJson(version) & """," & _
"""build"":""" & EscapeJson(build) & """," & _
"""platform"":""" & EscapeJson(platform) & """," & _
"""share"":""" & EscapeJson(share) & """" & _
"}"
Set file = filesystem.OpenTextFile(temporary, ForWriting, True)
file.Write json
file.Close
If filesystem.FileExists(destination) Then
filesystem.DeleteFile destination, True
End If
filesystem.MoveFile temporary, destination
End If
If Err.Number = 0 Then
On Error GoTo 0
Exit Do
End If
Err.Clear
On Error GoTo 0
WScript.Sleep 10000
Loop
VBSCRIPT
cat > "$RUNNER_TEMP/oem/install.bat" <<EOF
@echo off
cscript.exe //B //NoLogo C:\OEM\ready.vbs "$token"
EOF
;;
esac
echo "token=$token" >> "$GITHUB_OUTPUT"
- name: Pull image
shell: bash
run: |
set -Eeuo pipefail
docker pull "$IMAGE"
docker image inspect "$IMAGE" \
--format 'Digest: {{index .RepoDigests 0}}'
- name: Install and validate Windows
shell: bash
env:
CPU: ${{ inputs.cpu }}
EXPECTED_TOKEN: ${{ steps.test.outputs.token }}
EXPECTED_CAPTION: ${{ inputs.expected_caption }}
EXPECTED_EDITION: ${{ inputs.expected_edition }}
EXPECTED_PLATFORM: ${{ inputs.platform }}
MINIMUM_BUILD: ${{ inputs.minimum_build }}
VERSION: ${{ inputs.version }}
DISPLAY_NAME: ${{ inputs.name }}
run: |
set -Eeuo pipefail
docker run --detach \
--name "$CONTAINER" \
--device /dev/kvm \
--device /dev/net/tun \
--cap-add NET_ADMIN \
--stop-timeout 120 \
--env "VERSION=$VERSION" \
--env "RAM_SIZE=half" \
--env "CPU_CORES=half" \
--env "CPU_MODEL=$CPU" \
--env "DISK_SIZE=64G" \
--volume "$RUNNER_TEMP/data:/shared" \
--volume "$RUNNER_TEMP/oem:/oem:ro" \
--volume "$RUNNER_TEMP/storage:/storage" \
"$IMAGE"
echo
echo "Container log:"
echo "------------------------------------------------------------"
docker logs \
--follow \
--timestamps \
"$CONTAINER" &
logs_pid="$!"
stop_logs() {
kill "$logs_pid" 2>/dev/null || true
wait "$logs_pid" 2>/dev/null || true
}
trap stop_logs EXIT
deadline=$((SECONDS + 9000))
reboot_timeout=1800
minimum_reboots=1
boot_loop_limit=5
first_bios_start=-1
while (( SECONDS < deadline )); do
state="$(
docker inspect \
--format '{{.State.Status}}' \
"$CONTAINER" 2>/dev/null || true
)"
if [[ "$state" != "running" ]]; then
echo
echo "------------------------------------------------------------"
echo "Container stopped before Windows became ready."
echo "Container state: ${state:-missing}"
exit 1
fi
container_log="$(docker logs "$CONTAINER" 2>&1 || true)"
if grep -Eqi \
'KVM internal error|KVM: entry failed|hardware error 0x[0-9a-f]+|Triple fault' \
<<< "$container_log"; then
echo
echo "------------------------------------------------------------"
echo "Detected a fatal QEMU or KVM error."
exit 1
fi
if grep -Eqi \
'CDBOOT: Cannot boot from CD.*Code: 5' \
<<< "$container_log"; then
echo
echo "------------------------------------------------------------"
echo "The installation media could not be booted."
exit 1
fi
bios_starts="$(
grep -Fci 'SeaBIOS (version ' <<< "$container_log" || true
)"
hard_disk_boots="$(
grep -Fci 'Booting from Hard Disk' <<< "$container_log" || true
)"
dvd_boots="$(
grep -Fci 'Booting from DVD/CD' <<< "$container_log" || true
)"
not_bootable_disk="$(
grep -Fci \
'Boot failed: not a bootable disk' \
<<< "$container_log" || true
)"
unreadable_boot_disk="$(
grep -Fci \
'Boot failed: could not read the boot disk' \
<<< "$container_log" || true
)"
no_bootable_device="$(
grep -Fci 'No bootable device.' <<< "$container_log" || true
)"
bootmgr_missing="$(
grep -Fci 'BOOTMGR is missing' <<< "$container_log" || true
)"
reboots=$((bios_starts > 0 ? bios_starts - 1 : 0))
if (( first_bios_start < 0 && bios_starts > 0 )); then
first_bios_start=$SECONDS
fi
if (( first_bios_start >= 0 &&
SECONDS - first_bios_start >= reboot_timeout &&
reboots < minimum_reboots )); then
echo
echo "------------------------------------------------------------"
echo "The installation did not reboot within" \
"$((reboot_timeout / 60)) minutes after the first BIOS start."
echo "Observed reboots: $reboots"
echo "Required reboots: $minimum_reboots"
exit 1
fi
if (( bios_starts >= boot_loop_limit )) &&
(( hard_disk_boots >= boot_loop_limit ||
dvd_boots >= boot_loop_limit ||
not_bootable_disk >= boot_loop_limit ||
unreadable_boot_disk >= boot_loop_limit ||
no_bootable_device >= boot_loop_limit ||
bootmgr_missing >= boot_loop_limit )); then
echo
echo "------------------------------------------------------------"
echo "Detected a repeated BIOS boot loop."
echo "SeaBIOS starts: $bios_starts"
echo "Hard disk boots: $hard_disk_boots"
echo "DVD boots: $dvd_boots"
echo "Not-bootable disk failures: $not_bootable_disk"
echo "Unreadable boot-disk failures: $unreadable_boot_disk"
echo "No-bootable-device failures: $no_bootable_device"
echo "BOOTMGR failures: $bootmgr_missing"
exit 1
fi
response=""
if [[ -s "$RUNNER_TEMP/data/windows.json" ]]; then
response="$(cat "$RUNNER_TEMP/data/windows.json")"
fi
if [[ -n "$response" ]]; then
stop_logs
trap - EXIT
echo
echo "------------------------------------------------------------"
echo "Received response:"
if ! jq . <<< "$response"; then
echo "$response"
echo "The guest returned invalid JSON."
exit 1
fi
token="$(jq -r '.token // empty' <<< "$response")"
caption="$(jq -r '.caption // empty' <<< "$response")"
edition="$(jq -r '.edition // empty' <<< "$response")"
version="$(jq -r '.version // empty' <<< "$response")"
build="$(jq -r '.build // empty' <<< "$response")"
platform="$(jq -r '.platform // empty' <<< "$response")"
share="$(jq -r '.share // empty' <<< "$response")"
if [[ "$token" != "$EXPECTED_TOKEN" ]]; then
echo "The response token does not match."
exit 1
fi
if [[ "$share" != "$EXPECTED_TOKEN" ]]; then
echo "Failed to read \\\\host.lan\\Data\\readme.txt."
echo "Expected contents:"
echo " $EXPECTED_TOKEN"
echo "Received:"
echo " ${share:-empty}"
exit 1
fi
normalized_caption="${caption//\(R\)/}"
normalized_expected_caption="${EXPECTED_CAPTION//\(R\)/}"
if [[ "$normalized_caption" != *"$normalized_expected_caption"* ]]; then
echo "Expected caption containing:"
echo " $EXPECTED_CAPTION"
echo "Received:"
echo " $caption"
exit 1
fi
normalized_edition="${edition%Eval}"
normalized_expected_edition="${EXPECTED_EDITION%Eval}"
if [[ -n "$EXPECTED_EDITION" &&
"$normalized_edition" != "$normalized_expected_edition" ]]; then
echo "Expected edition: $EXPECTED_EDITION"
echo "Received edition: $edition"
exit 1
fi
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Unexpected Windows version: $version"
exit 1
fi
if [[ ! "$build" =~ ^[0-9]+$ ]]; then
echo "Invalid Windows build number: $build"
exit 1
fi
if (( build < MINIMUM_BUILD )); then
echo "Expected build $MINIMUM_BUILD or newer."
echo "Received build: $build"
exit 1
fi
if [[ "$platform" != "$EXPECTED_PLATFORM" ]]; then
echo "Expected platform:"
echo " $EXPECTED_PLATFORM"
echo "Received platform:"
echo " $platform"
exit 1
fi
echo
echo "$DISPLAY_NAME installed successfully."
echo "Version: $version"
echo "Build: $build"
echo "Platform: $platform"
echo "Shared file: accessible"
exit 0
fi
sleep 10
done
echo
echo "------------------------------------------------------------"
echo "Timed out waiting for Windows installation."
exit 1
- name: Cleanup
if: always()
shell: bash
run: |
docker rm --force "$CONTAINER" 2>/dev/null || true
+107 -5
View File
@@ -2,6 +2,8 @@ name: Links
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
concurrency:
group: links
@@ -22,29 +24,63 @@ jobs:
with:
fetch-depth: 0
-
name: Validate Links
name: Validate all download mirrors
id: validate
run: |
errors=0
count=0
skipped=0
tested=0
host=""
failed_links=""
failed_links_html=""
declare -A seen
ignored_domains=(
files.dog
bobpony.com
)
wget https://github.com/lwthiker/curl-impersonate/releases/download/v0.6.1/curl-impersonate-v0.6.1.x86_64-linux-gnu.tar.gz
tar -xzf curl-impersonate-v0.6.1.x86_64-linux-gnu.tar.gz
sudo cp curl-impersonate-ff /usr/local/bin/
check() {
local url="$1" http
http=$(curl-impersonate-ff -sSL -o /dev/null -w "%{http_code}" --max-time 10 -I -- "$url" 2>&1) || http="000"
[[ "$http" == 2* ]] && return 0
http=$(curl-impersonate-ff -sSL -o /dev/null -w "%{http_code}" --max-time 10 -r "0-0" -- "$url" 2>&1) || http="000"
[[ "$http" == 2* ]]
}
isIgnoredDomain() {
local url="$1"
local domain ignored
domain="${url#*://}"
domain="${domain%%/*}"
domain="${domain%%:*}"
domain="${domain,,}"
for ignored in "${ignored_domains[@]}"; do
if [[ "$domain" == "$ignored" || "$domain" == *."$ignored" ]]; then
return 0
fi
done
return 1
}
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]*local[[:space:]]+host=\"(https://[^\"]+)\" ]]; then
host="${BASH_REMATCH[1]%/}"
continue
fi
[[ "$line" =~ ^[[:space:]]*url=\"(.+)\" ]] || continue
val="${BASH_REMATCH[1]#/}"
if [[ "$val" == https://* ]]; then
url="$val"
elif [[ -n "$host" ]]; then
@@ -52,16 +88,82 @@ jobs:
else
continue
fi
[[ -v seen[$url] ]] && continue
seen[$url]=1
count=$((count + 1))
if isIgnoredDomain "$url"; then
echo "SKIP: $url (ignored domain)"
skipped=$((skipped + 1))
continue
fi
tested=$((tested + 1))
if check "$url"; then
echo " OK: $url"
else
echo "FAIL: $url"
errors=$((errors + 1))
failed_links+="$url"$'\n'
failed_links_html+="<li><a href=\"$url\">$url</a></li>"$'\n'
fi
done < "src/define.sh"
echo ""
printf '%d/%d links valid\n' "$(( count - errors ))" "$count"
(( errors == 0 ))
printf '%d/%d tested links valid\n' "$((tested - errors))" "$tested"
if (( skipped > 0 )); then
printf '%d link(s) skipped for ignored domains\n' "$skipped"
fi
if (( errors > 0 )); then
printf '%d blocking failure(s)\n' "$errors"
{
echo "failed=true"
echo "links<<EOF"
printf '%s' "$failed_links"
echo "EOF"
echo "html_links<<EOF"
printf '%s' "$failed_links_html"
echo "EOF"
} >> "$GITHUB_OUTPUT"
else
echo "failed=false" >> "$GITHUB_OUTPUT"
fi
-
name: Send mail
if: steps.validate.outputs.failed == 'true'
uses: action-pack/send-mail@v1
with:
to: ${{secrets.MAILTO}}
from: Github Actions <${{secrets.MAILTO}}>
connection_url: ${{secrets.MAIL_CONNECTION}}
subject: Mirror verification failed!
body: |
Mirror verification failed!
The following links failed:
${{ steps.validate.outputs.links }}
See https://github.com/${{ github.repository }}/actions for more information.
html_body: |
<p>Mirror verification failed!</p>
<p>The following links failed:</p>
<ul>
${{ steps.validate.outputs.html_links }}
</ul>
<p>
See
<a href="https://github.com/${{ github.repository }}/actions">GitHub Actions</a>
for more information.
</p>
-
name: Fail workflow
if: always() && steps.validate.outputs.failed == 'true'
run: exit 1
+249
View File
@@ -0,0 +1,249 @@
name: Validation
on:
release:
types:
- published
workflow_dispatch:
permissions:
contents: read
concurrency:
group: validation-${{ github.ref }}
cancel-in-progress: true
jobs:
desktop:
strategy:
fail-fast: false
matrix:
include:
- name: Windows 11 Pro
version: "11"
expected_caption: Windows 11
expected_edition: Professional
minimum_build: 22000
platform: x64
- name: Windows 11 LTSC
version: "11l"
expected_caption: Windows 11
expected_edition: EnterpriseS
minimum_build: 26100
platform: x64
- name: Windows 11 Enterprise
version: "11e"
expected_caption: Windows 11
expected_edition: Enterprise
minimum_build: 22000
platform: x64
- name: Windows 11 IoT Enterprise
version: "11i"
expected_caption: Windows 11
expected_edition: IoTEnterpriseS
minimum_build: 26100
platform: x64
- name: Windows 10 Pro
version: "10"
expected_caption: Windows 10
expected_edition: Professional
minimum_build: 10240
platform: x64
- name: Windows 10 LTSC
version: "10l"
expected_caption: Windows 10
expected_edition: EnterpriseS
minimum_build: 17763
platform: x64
- name: Windows 10 Enterprise
version: "10e"
expected_caption: Windows 10
expected_edition: Enterprise
minimum_build: 10240
platform: x64
- name: Windows 10 IoT Enterprise
version: "10i"
expected_caption: Windows 10
expected_edition: IoTEnterpriseS
minimum_build: 19044
platform: x64
- name: Windows 8.1 Enterprise
version: "8e"
expected_caption: Windows 8.1
expected_edition: Enterprise
minimum_build: 9600
platform: x64
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
expected_caption: ${{ matrix.expected_caption }}
expected_edition: ${{ matrix.expected_edition }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
tiny:
strategy:
fail-fast: false
matrix:
include:
- name: Core11
version: "core11"
expected_caption: Windows 11
minimum_build: 22000
platform: x64
- name: Tiny11
version: "tiny11"
expected_caption: Windows 11
minimum_build: 22000
platform: x64
- name: Tiny10
version: "tiny10"
expected_caption: Windows 10
minimum_build: 19041
platform: x64
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
expected_caption: ${{ matrix.expected_caption }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
server:
strategy:
fail-fast: false
matrix:
include:
- name: Windows Server 2025
version: "2025"
expected_caption: Windows Server 2025
minimum_build: 26100
platform: x64
- name: Windows Server 2022
version: "2022"
expected_caption: Windows Server 2022
minimum_build: 20348
platform: x64
- name: Windows Server 2019
version: "2019"
expected_caption: Windows Server 2019
minimum_build: 17763
platform: x64
- name: Windows Server 2016
version: "2016"
expected_caption: Windows Server 2016
minimum_build: 14393
platform: x64
- name: Windows Server 2012 R2
version: "2012"
expected_caption: Windows Server 2012 R2
minimum_build: 9600
platform: x64
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
expected_caption: ${{ matrix.expected_caption }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
legacy:
strategy:
fail-fast: false
matrix:
include:
- name: Windows 7 Ultimate
version: "7u"
cpu: host
expected_caption: Windows 7
minimum_build: 7601
platform: x64
- name: Windows 7 Ultimate x86
version: "7x86"
cpu: host
expected_caption: Windows 7
minimum_build: 7601
platform: x86
- name: Windows Vista Ultimate
version: "vu"
cpu: host
expected_caption: Windows Vista
minimum_build: 6002
platform: x64
- name: Windows Vista Ultimate x86
version: "vistax86"
cpu: host
expected_caption: Windows Vista
minimum_build: 6002
platform: x86
- name: Windows XP Professional
version: "xp"
cpu: host
expected_caption: Windows XP
minimum_build: 2600
platform: x86
- name: Windows XP Professional x64
version: "xp64"
cpu: host
expected_caption: Windows XP
minimum_build: 3790
platform: x64
- name: Windows 2000 Professional
version: "2k"
cpu: host
expected_caption: Windows 2000
minimum_build: 2195
platform: x86
- name: Windows Server 2008 R2
version: "2008"
cpu: host
expected_caption: Windows Server 2008 R2
minimum_build: 7601
platform: x64
- name: Windows Server 2003 R2
version: "2003"
cpu: host
expected_caption: Windows Server 2003
minimum_build: 3790
platform: x64
name: ${{ matrix.name }}
uses: ./.github/workflows/install.yml
with:
name: ${{ matrix.name }}
version: ${{ matrix.version }}
callback: legacy
cpu: ${{ matrix.cpu }}
expected_caption: ${{ matrix.expected_caption }}
minimum_build: ${{ matrix.minimum_build }}
platform: ${{ matrix.platform }}
+9 -1
View File
@@ -3,11 +3,12 @@
ARG VERSION_ARG="latest"
FROM scratch AS build-amd64
COPY --from=qemux/qemu:7.39 / /
COPY --from=qemux/qemu:7.40 / /
ARG TARGETARCH
ARG VERSION_WSDD="1.26"
ARG VERSION_VIRTIO="1.9.58"
ARG VERSION_BLINTER="1.0.112"
ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
@@ -22,9 +23,16 @@ RUN <<EOF
wimtools \
dos2unix \
cabextract \
icu-devtools \
libxml2-utils \
libarchive-tools
# Install Blinter
python3 -m pip install \
--break-system-packages \
--no-cache-dir \
"Blinter==${VERSION_BLINTER}"
# Install wsdd
wget "https://github.com/gershnik/wsdd-native/releases/download/v${VERSION_WSDD}/wsddn_${VERSION_WSDD}_${TARGETARCH}.deb" -O /tmp/wsddn.deb -q --timeout=10
dpkg -i /tmp/wsddn.deb
+1 -1
View File
@@ -251,7 +251,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -257,7 +257,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -254,7 +254,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -251,7 +251,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+2 -2
View File
@@ -269,12 +269,12 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>pnputil -i -a C:\Windows\Drivers\viogpudo\viogpudo.inf</Path>
<Path>cmd.exe /c start "" /b /wait pnputil -i -a "C:\Windows\Drivers\viogpudo\viogpudo.inf"</Path>
<Description>Install VirtIO display driver</Description>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>27</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+2 -2
View File
@@ -269,12 +269,12 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>pnputil -i -a C:\Windows\Drivers\viogpudo\viogpudo.inf</Path>
<Path>cmd.exe /c start "" /b /wait pnputil -i -a "C:\Windows\Drivers\viogpudo\viogpudo.inf"</Path>
<Description>Install VirtIO display driver</Description>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>27</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+2 -2
View File
@@ -269,12 +269,12 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>pnputil -i -a C:\Windows\Drivers\viogpudo\viogpudo.inf</Path>
<Path>cmd.exe /c start "" /b /wait pnputil -i -a "C:\Windows\Drivers\viogpudo\viogpudo.inf"</Path>
<Description>Install VirtIO display driver</Description>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>27</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+2 -2
View File
@@ -269,12 +269,12 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Path>pnputil -i -a C:\Windows\Drivers\viogpudo\viogpudo.inf</Path>
<Path>cmd.exe /c start "" /b /wait pnputil -i -a "C:\Windows\Drivers\viogpudo\viogpudo.inf"</Path>
<Description>Install VirtIO display driver</Description>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>27</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -161,7 +161,7 @@
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -160,7 +160,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>2</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -160,7 +160,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>2</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -166,7 +166,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>3</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -164,7 +164,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>2</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -164,7 +164,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>2</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+2 -2
View File
@@ -164,12 +164,12 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>2</Order>
<Path>pnputil -i -a C:\Windows\Drivers\viogpudo\viogpudo.inf</Path>
<Path>cmd.exe /c start "" /b /wait pnputil -i -a "C:\Windows\Drivers\viogpudo\viogpudo.inf"</Path>
<Description>Install VirtIO display driver</Description>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>4</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -156,7 +156,7 @@
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -156,7 +156,7 @@
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -156,7 +156,7 @@
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -151,7 +151,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>2</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -158,7 +158,7 @@
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>2</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -94,7 +94,7 @@
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -94,7 +94,7 @@
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+1 -1
View File
@@ -94,7 +94,7 @@
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>C:\Windows\Drivers\Balloon\blnsvr.exe -i</Path>
<Path>cmd.exe /c start "" /b /wait "C:\Windows\Drivers\Balloon\blnsvr.exe" -i</Path>
<Description>Install VirtIO Balloon service</Description>
</RunSynchronousCommand>
</RunSynchronous>
+3
View File
@@ -112,6 +112,7 @@ An empty default means the variable is unset and its value is determined automat
| Variable | Default | Description |
|---|---|---|
| `MACHINE` | `q35` | QEMU machine type. |
| `PCI_BUS` | `pcie.0` | Overrides the PCI bus used for attached devices. |
| `UUID` | | UUID assigned to Windows. |
| `HPET` | `off` | QEMU HPET timer setting. |
| `VMPORT` | `off` | QEMU VMware port setting. |
@@ -160,6 +161,7 @@ Also see [Dynamic memory allocation](https://github.com/qemus/qemu/blob/master/d
| `VERIFY` | `N` | Verifies downloaded installation media against predefined checksums. |
| `REMOVE` | `Y` | Deletes the downloaded Windows ISO after installation to save space. |
| `MANUAL` | `N` | Enables manual installation instead of unattended installation. |
| `REBUILD` | `Y` | Skips rebuilding the Windows ISO and uses the original image unchanged. |
| `COMMAND` | | Command to be executed during the final step of automatic installation. |
## 🔌 Shutdown
@@ -175,6 +177,7 @@ Also see [Dynamic memory allocation](https://github.com/qemus/qemu/blob/master/d
|---|---|---|
| `DEBUG` | `N` | Enables verbose debug output. |
| `TRACE` | `N` | Enables shell command tracing. |
| `LOG` | `N` | Saves all output from `install.bat` to `C:\OEM\install.log` for troubleshooting. |
| `DETECTED` | | Overrides the automatically detected Windows image identifier. |
| `SERIAL` | `mon:stdio` | QEMU serial device configuration. |
| `MONITOR` | `unix:$QEMU_DIR/monitor.sock,server,wait=off,nodelay` | QEMU monitor configuration. |
+979 -564
View File
File diff suppressed because it is too large Load Diff
+529 -301
View File
File diff suppressed because it is too large Load Diff
+1182 -327
View File
File diff suppressed because it is too large Load Diff
+112 -155
View File
@@ -11,7 +11,7 @@ backup () {
local count=1
local name="unknown"
local root="$STORAGE/backups"
local file previous find_pid failed=""
local file previous failed=""
previous=$(readState "base") || return 1
[ -n "$previous" ] && name="${previous%.*}"
@@ -53,7 +53,7 @@ backup () {
-not -iname '*.iso' -print0
)
find_pid=$!
local find_pid=$!
if ! wait "$find_pid"; then
error "Failed to enumerate files in \"$STORAGE\"."
@@ -122,10 +122,8 @@ detectCustom() {
skipInstall() {
local iso="$1"
local method=""
local magic byte
local method magic previous
local boot="$STORAGE/windows.boot"
local previous
previous=$(readState "base") || return 1
@@ -178,7 +176,8 @@ skipInstall() {
# Check if the ISO was already processed by our script
magic=$(dd if="$iso" bs=1 count=1 status=none | tr -d '\000')
magic="$(printf '%s' "$magic" | od -A n -t x1 -v | tr -d ' \n')"
byte="16" && enabled "$MANUAL" && byte="17"
local byte="16"
enabled "$MANUAL" && byte="17"
if [[ "$magic" != "$byte" ]]; then
@@ -293,7 +292,7 @@ finishInstall() {
local iso="$1"
local aborted="$2"
local base byte
local base
if [ ! -s "$iso" ] || [ ! -f "$iso" ]; then
error "Failed to find ISO file: $iso" && return 1
@@ -307,7 +306,8 @@ finishInstall() {
if [[ "$aborted" != [Yy1]* ]]; then
# Mark ISO as prepared via magic byte
byte="16" && enabled "$MANUAL" && byte="17"
local byte="16"
enabled "$MANUAL" && byte="17"
if ! printf '%b' "\x$byte" | dd of="$iso" bs=1 seek=0 count=1 conv=notrunc status=none; then
warn "failed to set magic byte in ISO file: $iso"
fi
@@ -374,6 +374,10 @@ finishInstall() {
writeState "sound" "$SOUND" || return 1
fi
if [ -n "${CPU_MODEL:-}" ] && [[ "${CPU_MODEL,,}" != "host" ]]; then
writeState "cpu" "$CPU_MODEL" || return 1
fi
rm -rf "$TMP"
return 0
}
@@ -443,21 +447,18 @@ extractESD() {
local version="$3"
local desc="$4"
local msg ret index size
local minSize freeSpace bootPad
local info count totals links
local bootTotal bootLinks bootSize
local wimTotal wimLinks wimSize
local installSize installPad
local bootWim installWim
local bootTotal bootLinks
local wimTotal wimLinks
local installSize size
local edition imgEdition
minSize=100000000
freeSpace=9606127360
bootPad=60000000
installPad=3000000
local minSize=100000000
local freeSpace=9606127360
local bootPad=60000000
local installPad=3000000
msg="Extracting $desc bootdisk"
local msg="Extracting $desc bootdisk"
info "$msg..." && html "$msg..."
if ! size=$(stat -c%s -- "$iso"); then
@@ -510,7 +511,7 @@ extractESD() {
return 1
fi
bootSize=$(( bootTotal - bootLinks ))
local bootSize=$(( bootTotal - bootLinks ))
wimTotal=$(getEsdField "$totals" 3)
wimLinks=$(getEsdField "$links" 3)
@@ -520,13 +521,13 @@ extractESD() {
return 1
fi
wimSize=$(( wimTotal - wimLinks + bootPad ))
local wimSize=$(( wimTotal - wimLinks + bootPad ))
/run/progress.sh "$dir" "$bootSize" "$msg ([P])..." &
index="1"
local index="1"
wimlib-imagex apply "$iso" "$index" "$dir" --quiet 2>/dev/null || {
ret=$?
local ret=$?
fKill "progress.sh"
error "Extracting $desc bootdisk failed ($ret)"
return 1
@@ -534,8 +535,8 @@ extractESD() {
fKill "progress.sh"
bootWim="$dir/sources/boot.wim"
installWim="$dir/sources/install.wim"
local bootWim="$dir/sources/boot.wim"
local installWim="$dir/sources/install.wim"
msg="Extracting $desc environment"
info "$msg..." && html "$msg..."
@@ -544,7 +545,7 @@ extractESD() {
/run/progress.sh "$bootWim" "$wimSize" "$msg ([P])..." &
wimlib-imagex export "$iso" "$index" "$bootWim" --compress=none --quiet || {
ret=$?
local ret=$?
fKill "progress.sh"
error "Adding WinPE failed ($ret)"
return 1
@@ -559,7 +560,7 @@ extractESD() {
/run/progress.sh "$bootWim" "$wimSize" "$msg ([P])..." &
wimlib-imagex export "$iso" "$index" "$bootWim" --compress=none --boot --quiet || {
ret=$?
local ret=$?
fKill "progress.sh"
error "Adding Windows Setup failed ($ret)"
return 1
@@ -594,7 +595,7 @@ extractESD() {
/run/progress.sh "$installWim" "$installSize" "$msg ([P])..." &
wimlib-imagex export "$iso" "$index" "$installWim" --compress=LZMS --chunk-size 128K --quiet || {
ret=$?
local ret=$?
fKill "progress.sh"
error "Addition of $index to the $desc image failed ($ret)"
return 1
@@ -695,25 +696,27 @@ setMachine() {
local iso="$2"
local dir="$3"
local desc="$4"
local legacy=""
if ! disabled "$REBUILD"; then
case "${id,,}" in
"win2k"* ) legacy="2k" ;;
"winxp"* ) legacy="xp" ;;
"win2003"* ) legacy="2k3" ;;
esac
if [ -n "$legacy" ]; then
if ! legacyInstall "$iso" "$dir" "$desc" "$legacy"; then
error "Failed to prepare $desc ISO!"
return 1
fi
fi
fi
case "${id,,}" in
"win9"* )
ETFS="[BOOT]/Boot-1.44M.img" ;;
"win2k"* )
if ! legacyInstall "$iso" "$dir" "$desc" "2k"; then
error "Failed to prepare $desc ISO!" && return 1
fi ;;
"winxp"* )
if ! legacyInstall "$iso" "$dir" "$desc" "xp"; then
error "Failed to prepare $desc ISO!" && return 1
fi ;;
"win2003"* )
if ! legacyInstall "$iso" "$dir" "$desc" "2k3"; then
error "Failed to prepare $desc ISO!" && return 1
fi ;;
esac
case "${id,,}" in
"win9"* )
USB="no"
VGA="cirrus"
@@ -721,6 +724,7 @@ setMachine() {
MACHINE="pc-i440fx-2.4"
BOOT_MODE="windows_legacy"
[ -z "${ADAPTER:-}" ] && ADAPTER="pcnet" ;;
"win2k"* )
VGA="cirrus"
MACHINE="pc"
@@ -728,18 +732,38 @@ setMachine() {
DISK_TYPE="auto"
BOOT_MODE="windows_legacy"
[ -z "${ADAPTER:-}" ] && ADAPTER="rtl8139" ;;
"winxp"* | "win2003"* )
"winxp"* )
DISK_TYPE="blk"
BOOT_MODE="windows_legacy"
[ -z "${SOUND:-}" ] && SOUND="usb-audio"
if [ -z "${CPU_MODEL:-}" ] || [[ "${CPU_MODEL:-}" == "host" ]]; then
# Workaround for boot loop on AMD EPYC processors
if [[ "${id,,}" == "winxpx86"* && "${CPU,,}" == *"amd epyc"* ]]; then
CPU_MODEL="qemu32"
fi
fi ;;
"win2003"* )
DISK_TYPE="blk"
BOOT_MODE="windows_legacy"
[ -z "${SOUND:-}" ] && SOUND="usb-audio" ;;
"winvista"* | "win7"* | "win2008"* )
BOOT_MODE="windows_legacy" ;;
esac
case "${id,,}" in
"winxp"* | "win2003"* | "winvistax86"* | "win7x86"* | "win2008r2x86"* )
# Prevent bluescreen if 64 bit PCI hole size is >2G.
ARGS="-global q35-pcihost.x-pci-hole64-fix=false" ;;
if isQ35 "${MACHINE:-q35}"; then
# Prevent bluescreen if 64 bit PCI hole size is >2G.
ARGS="-global q35-pcihost.x-pci-hole64-fix=false"
fi ;;
esac
return 0
@@ -753,33 +777,42 @@ prepareImage() {
desc=$(printVariant "$DETECTED" "$DETECTED")
# Adjust QEMU machine configuration for legacy versions
setMachine "$DETECTED" "$iso" "$dir" "$desc" || return 1
disabled "$REBUILD" && return 0
if [[ "${BOOT_MODE,,}" == "windows_legacy" &&
"${DETECTED,,}" != "win9"* ]]; then
getBootLoadSize "$iso" "$dir" "$desc" || return 1
fi
skipVersion "$DETECTED" && return 0
if [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
[ -f "$dir/$ETFS" ] && [ -s "$dir/$ETFS" ] &&
[ -f "$dir/$EFISYS" ] && [ -s "$dir/$EFISYS" ] && return 0
missing=$(basename "$dir/$EFISYS")
if [ ! -f "$dir/$ETFS" ] || [ ! -s "$dir/$ETFS" ]; then
missing=$(basename "$dir/$ETFS")
fi
extractBootImage "$iso" "$dir" "$desc" && return 0
error "Failed to locate file \"${missing,,}\" in ISO image!"
error "Failed to extract boot image from ISO image \"${iso}\"!"
return 1
fi
legacyPrepare "$iso" "$dir" "$desc" && return 0
[ -f "$dir/$ETFS" ] && [ -s "$dir/$ETFS" ] &&
[ -f "$dir/$EFISYS" ] && [ -s "$dir/$EFISYS" ] && return 0
error "Failed to extract boot image from ISO image!"
missing=$(basename "$dir/$EFISYS")
if [ ! -f "$dir/$ETFS" ] || [ ! -s "$dir/$ETFS" ]; then
missing=$(basename "$dir/$ETFS")
fi
error "Failed to locate file \"${missing,,}\" in ISO image!"
return 1
}
addFolder() {
local src="$1"
local folder="/oem" file=""
local folder="/oem" file
local dest="$src/\$OEM\$/\$1/OEM"
[ ! -d "$folder" ] && folder="/OEM"
@@ -800,6 +833,10 @@ addFolder() {
file=$(find "$dest" -maxdepth 1 -type f -iname install.bat -print -quit) || return 1
if [ -s "$file" ]; then
normalizeBatch "$file" || return 1
fi
if [ -n "$COMMAND" ]; then
[ -z "$file" ] && file="$dest/install.bat"
@@ -812,11 +849,14 @@ addFolder() {
fi
if [ -f "$file" ]; then
if [ -s "$file" ]; then
if ! unix2dos -q "$file"; then
error "Failed to convert $file to DOS format!"
return 1
fi
checkBatch "$file"
fi
return 0
@@ -828,8 +868,7 @@ addDriver() {
local path="$2"
local target="$3"
local driver="$4"
local desc=""
local folder=""
local folder="" desc
if [ -z "$id" ]; then
warn "no Windows version specified for \"$driver\" driver!" && return 0
@@ -942,7 +981,12 @@ updateImage() {
local xml="autounattend.xml"
local bak="${xml//.xml/.org}"
local dat="${xml//.xml/.dat}"
local desc path src wim name info idx
local desc path src wim name info
if disabled "$REBUILD"; then
info "Skipping modifications to the installation image..."
return 1
fi
skipVersion "${DETECTED,,}" && return 0
@@ -971,7 +1015,7 @@ updateImage() {
return 1
fi
idx="1"
local idx="1"
if ! info=$(wimlib-imagex info -xml "$wim" | iconv -f UTF-16LE -t UTF-8); then
warn "failed to read boot image information, $FB"
@@ -1013,23 +1057,7 @@ updateImage() {
return 1
fi
local fallback="/run/assets/${DETECTED%%-*}.xml"
if [[ "$DETECTED" != win20* &&
"$asset" == "$fallback" &&
"$asset" != "/run/assets/$DETECTED.xml" ]]; then
if ! sed -i \
-e '/<InstallFrom>.*<\/InstallFrom>/d' \
-e '/<ProductKey>.*<\/ProductKey>/d' \
-e '/<InstallFrom>/,/<\/InstallFrom>/d' \
-e '/<ProductKey>/,/<\/ProductKey>/d' \
"$answer"; then
error "Failed to make answer file edition-neutral: $answer"
return 1
fi
fi
removeGeneratedXML "$asset" || return 1
if [ -n "${CUSTOM_XML:-}" ]; then
@@ -1058,6 +1086,8 @@ updateImage() {
if enabled "$MANUAL"; then
removeGeneratedXML "$asset" || return 1
wimlib-imagex update "$wim" "$idx" --command "delete --force /$xml" > /dev/null || true
if wimlib-imagex extract "$wim" "$idx" "/$bak" "--dest-dir=$tmp" >/dev/null 2>&1; then
@@ -1102,80 +1132,6 @@ removeImage() {
return 0
}
buildImage() {
local dir="$1"
local failed=""
local cat="BOOT.CAT"
local log="/run/shm/iso.log"
local base size desc
if [ -f "$BOOT" ]; then
error "File $BOOT does already exist?!" && return 1
fi
base=$(basename "$BOOT")
local out="$TMP/${base%.*}.tmp"
rm -f "$out"
desc=$(printVariant "$DETECTED" "ISO")
local msg="Building $desc image"
info "$msg..." && html "$msg..."
[ -z "$LABEL" ] && LABEL="Windows"
if [ ! -f "$dir/$ETFS" ] || [ ! -s "$dir/$ETFS" ]; then
error "Failed to locate file \"$ETFS\" in ISO image!" && return 1
fi
size=$(du -b --max-depth=0 "$dir" | cut -f1)
checkFreeSpace "$TMP" "$size" || return 1
/run/progress.sh "$out" "$size" "$msg ([P])..." &
if [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then
genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 4 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
-udf -boot-info-table -eltorito-alt-boot -eltorito-boot "$EFISYS" -no-emul-boot -allow-limited-size -quiet "$dir" 2> "$log" || failed="y"
else
case "${DETECTED,,}" in
"win2k"* | "winxp"* | "win2003"* )
genisoimage -o "$out" -b "$ETFS" -no-emul-boot -boot-load-seg 1984 -boot-load-size 4 -c "$cat" -iso-level 2 -J -l -D -N -joliet-long \
-relaxed-filenames -V "${LABEL::30}" -quiet "$dir" 2> "$log" || failed="y" ;;
"win9"* )
genisoimage -o "$out" -b "$ETFS" -J -r -V "${LABEL::30}" -quiet "$dir" 2> "$log" || failed="y" ;;
* )
genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 2 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
-udf -allow-limited-size -quiet "$dir" 2> "$log" || failed="y" ;;
esac
fi
fKill "progress.sh"
if [ -n "$failed" ]; then
[ -s "$log" ] && echo "$(<"$log")"
error "Failed to build image!" && return 1
fi
local err=""
local hide="Warning: creating filesystem that does not conform to ISO-9660."
[ -s "$log" ] && err="$(<"$log")"
[[ "$err" != "$hide" ]] && echo "$err"
mv -f "$out" "$BOOT" || return 1
if ! setOwner "$BOOT"; then
warn "Failed to set the owner for \"$BOOT\" !"
fi
return 0
}
bootWindows() {
ARGS=$(readState "$STORAGE/windows.args") || return 1
@@ -1188,6 +1144,7 @@ bootWindows() {
restoreState "USB" "$STORAGE/windows.usb" || return 1
restoreState "SOUND" "$STORAGE/windows.sound" || return 1
restoreState "ADAPTER" "$STORAGE/windows.net" || return 1
restoreState "CPU_MODEL" "$STORAGE/windows.cpu" || return 1
restoreState "DISK_TYPE" "$STORAGE/windows.type" || return 1
restoreState "BOOT_MODE" "$STORAGE/windows.mode" "Y" || return 1
+85 -46
View File
@@ -6,7 +6,7 @@ handleCurlError() {
local code="$1"
local server="$2"
local reason="${3:-}"
local signal=""
local signal
if [ -n "$reason" ] && (( code <= 125 )); then
error "Request to $server servers failed: ${reason%.}."
@@ -43,8 +43,7 @@ curlRequest() {
local agent="$3"
shift 3
local log reason
local rc=0 response=""
local log reason response
if ! log=$(mktemp -p "$QEMU_DIR"); then
error "Failed to create a temporary curl log."
@@ -62,7 +61,7 @@ curlRequest() {
--tlsv1.2 \
--http1.1 \
"$@" 2>"$log")
rc=$?
local rc=$?
} || :
if (( rc != 0 )); then
@@ -90,14 +89,14 @@ downloadWindows() {
local lang="$2"
local desc="$3"
local ovToken="" ovTicks="" ovTime=""
local skuId="" skuUrl="" skuJson=""
local linkUrl="" linkJson="" link=""
local language="" orgId="" ovData=""
local instance="" vlsUrl="" ovUrl=""
local session="" agent="" type=""
local winVer="" page="" productId=""
local rc=0 profile="606624d44113"
local ovToken="" ovTicks="" ovTime
local skuId skuJson
local linkJson link
local language ovData
local session agent
local type winVer
local page productId
local profile="606624d44113"
agent=$(getAgent)
language=$(getLanguage "$lang" "name")
@@ -142,8 +141,8 @@ downloadWindows() {
# Microsoft download "protection" requires the sessionId to be whitelisted through vlscppe.microsoft.com/tags
orgId="y6jn8c31"
vlsUrl="https://vlscppe.microsoft.com/tags?org_id=$orgId&session_id=$session"
local orgId="y6jn8c31"
local vlsUrl="https://vlscppe.microsoft.com/tags?org_id=$orgId&session_id=$session"
enabled "$DEBUG" && echo "Getting Session ID: $session"
@@ -157,8 +156,8 @@ downloadWindows() {
# Microsoft download "protection" also requires an ov-df.microsoft.com request/reply
# 1) Request mdt.js to get w and rticks. InstanceId is (currently) constant.
instance="560dc9f3-1aa5-4a2f-b63c-9e18f8d0e175"
ovUrl="https://ov-df.microsoft.com/mdt.js?instanceId=$instance&PageId=si&session_id=$session"
local instance="560dc9f3-1aa5-4a2f-b63c-9e18f8d0e175"
local ovUrl="https://ov-df.microsoft.com/mdt.js?instanceId=$instance&PageId=si&session_id=$session"
enabled "$DEBUG" && echo -n "Getting OV data: "
@@ -199,7 +198,7 @@ downloadWindows() {
enabled "$DEBUG" && echo -n "Getting language SKU ID: "
skuUrl="https://www.microsoft.com/software-download-connector/api/getskuinformationbyproductedition?profile=$profile&ProductEditionId=$productId&SKU=undefined&friendlyFileName=undefined&Locale=en-US&sessionID=$session"
local skuUrl="https://www.microsoft.com/software-download-connector/api/getskuinformationbyproductedition?profile=$profile&ProductEditionId=$productId&SKU=undefined&friendlyFileName=undefined&Locale=en-US&sessionID=$session"
curlRequest skuJson "Microsoft" "$agent" \
--referer "$url" \
@@ -207,7 +206,7 @@ downloadWindows() {
--max-filesize 100K \
-- "$skuUrl" || return 1
{ skuId=$(echo "$skuJson" | jq --arg LANG "$language" -r '.Skus[] | select(.Language==$LANG).Id') 2>/dev/null; rc=$?; } || :
{ skuId=$(echo "$skuJson" | jq --arg LANG "$language" -r '.Skus[] | select(.Language==$LANG).Id') 2>/dev/null; local rc=$?; } || :
if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]] || (( rc != 0 )); then
language=$(getLanguage "$lang" "desc")
@@ -221,7 +220,7 @@ downloadWindows() {
# Get ISO download link
# If any request is going to be blocked by Microsoft it's always this last one (the previous requests always seem to succeed)
linkUrl="https://www.microsoft.com/software-download-connector/api/GetProductDownloadLinksBySku?profile=$profile&ProductEditionId=undefined&SKU=$skuId&friendlyFileName=undefined&Locale=en-US&sessionID=$session"
local linkUrl="https://www.microsoft.com/software-download-connector/api/GetProductDownloadLinksBySku?profile=$profile&ProductEditionId=undefined&SKU=$skuId&friendlyFileName=undefined&Locale=en-US&sessionID=$session"
curlRequest linkJson "Microsoft" "$agent" \
--referer "$url" \
@@ -262,8 +261,8 @@ downloadWindowsEval() {
local id="$1"
local lang="$2"
local desc="$3"
local filter="" culture="" compare="" language=""
local agent="" type="" winVer=""
local culture compare type
local agent language winVer
case "${id,,}" in
"win11${PLATFORM,,}-enterprise-eval" )
@@ -301,9 +300,7 @@ downloadWindowsEval() {
culture=$(getLanguage "$lang" "culture")
local country="${culture#*-}"
local link=""
local links=""
local page=""
local link="" links page
local url="https://www.microsoft.com/en-us/evalcenter/download-$winVer"
enabled "$DEBUG" && echo "Parsing download page: ${url}"
@@ -321,7 +318,7 @@ downloadWindowsEval() {
enabled "$DEBUG" && echo "Getting download link.."
filter="https://go.microsoft.com/fwlink/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
local filter="https://go.microsoft.com/fwlink/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
if ! echo "$page" | grep -io "$filter" > /dev/null; then
filter="https://go.microsoft.com/fwlink/p/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
@@ -383,15 +380,18 @@ downloadWindowsEval() {
--head \
-- "$link" || return 1
local lower="${link,,}"
local separator='(^|[[:space:]_./-])'
case "${PLATFORM,,}" in
"x64" )
if [[ "${link,,}" != *"x64"* ]]; then
if [[ "$lower" =~ ${separator}(arm64|a64) ]]; then
echo "Found download link: $link"
error "Download link is for the wrong platform? Please report this at $SUPPORT/issues"
return 1
fi ;;
"arm64" )
if [[ "${link,,}" != *"a64"* && "${link,,}" != *"arm64"* ]]; then
if [[ "$lower" =~ ${separator}(x64|x86|amd64) ]]; then
if enabled "$DEBUG"; then
echo "Found download link: $link"
echo "Link for ARM platform currently not available!"
@@ -401,10 +401,21 @@ downloadWindowsEval() {
esac
if enabled "$DEBUG" && enabled "$VERIFY" && [[ "${lang,,}" == "en"* ]]; then
compare=$(getMido "$id" "$lang" "")
if [ -n "$compare" ] && [[ "${link,,}" != "${compare,,}" ]]; then
echo "Retrieved link does not match the fixed link: $compare"
if [ -n "$compare" ]; then
link_name="${link%%[?#]*}"
link_name="${link_name##*/}"
compare_name="${compare%%[?#]*}"
compare_name="${compare_name##*/}"
if [[ "${link_name,,}" != "${compare_name,,}" ]]; then
echo "Retrieved ISO file $link_name does not match the pre-defined filename: $compare_name"
fi
fi
fi
MIDO_URL="$link"
@@ -455,7 +466,7 @@ getMidoDetected() {
detected="${source%-enterprise-ltsc-eval}-ltsc-eval"
;;
*"-enterprise-iot-eval" )
detected="${source%-enterprise-iot-eval}-iot"
detected="${source%-enterprise-iot-eval}-iot-eval"
;;
*"-eval" )
detected="$source"
@@ -474,8 +485,7 @@ downloadWindowsLtsc() {
local id="$1"
local lang="$2"
local desc="$3"
local alternate=""
local alternate_desc=""
local alternate alternate_desc
case "${id,,}" in
"win11${PLATFORM,,}-enterprise-iot-eval" )
@@ -691,7 +701,7 @@ getESD() {
local xmlFile="products.xml"
local esdFile="esd_edition.xml"
local filterFile="products_filter.xml"
local log query rc=0 reason=""
local log
file=$(getCatalog "$version" "file")
catalog=$(getCatalog "$version" "url")
@@ -721,11 +731,12 @@ getESD() {
{
LC_ALL=C wget "$catalog" -O "$dir/$file" --no-verbose --timeout=30 \
--no-http-keep-alive --output-file="$log"
rc=$?
local rc=$?
} || :
if (( rc != 0 )); then
local reason
reason=$(sed -n \
-e 's/^wget: //p' \
-e 's/^[0-9-]\{10\} [0-9:]\{8\} ERROR //p' \
@@ -771,7 +782,7 @@ getESD() {
return 1
fi
query='//File[Architecture="'${PLATFORM,,}'"]'"${edition}"''
local query='//File[Architecture="'${PLATFORM,,}'"]'"${edition}"''
result=$(xmllint --nonet --xpath "${query}" "$dir/$xmlFile" 2>/dev/null || true)
if [ -z "$result" ]; then
@@ -853,8 +864,8 @@ verifyFile() {
fi
fi
local hash=""
local algo="SHA256"
local hash
[ -z "$check" ] && return 0
! enabled "$VERIFY" && return 0
@@ -864,15 +875,31 @@ verifyFile() {
info "$msg" && html "$msg"
if [[ "${algo,,}" != "sha256" ]]; then
if ! hash=$(sha1sum "$iso" | cut -f1 -d' '); then
hash=$(sha1sum "$iso" | cut -f1 -d' ') || {
local rc=$?
if (( rc >= 129 )); then
exit "$rc"
fi
error "Failed to calculate SHA1 checksum for $iso!"
return 1
fi
}
else
if ! hash=$(sha256sum "$iso" | cut -f1 -d' '); then
hash=$(sha256sum "$iso" | cut -f1 -d' ') || {
local rc=$?
if (( rc >= 129 )); then
exit "$rc"
fi
error "Failed to calculate SHA256 checksum for $iso!"
return 1
fi
}
fi
if [[ "$hash" == "$check" ]]; then
@@ -923,7 +950,7 @@ tryDownload() {
local desc="$6"
local seconds="$7"
local web_desc="$8"
local total rc=0
local total
if downloadRetry \
"$iso" \
@@ -936,9 +963,9 @@ tryDownload() {
"$size" \
"$desc" \
"$web_desc"; then
rc=0
local rc=0
else
rc=$?
local rc=$?
fi
(( rc == 0 )) || return "$rc"
@@ -971,9 +998,9 @@ fallbackEnglish() {
local lang="$3"
local desc="$4"
local web_desc="$5"
local culture msg web_msg
local culture web_msg
msg="No working download method was found for $desc, falling back to English..."
local msg="No working download method was found for $desc, falling back to English..."
info "$msg"
# Preserve the requested regional format and keyboard layout.
@@ -998,6 +1025,7 @@ downloadImage() {
local iso="$1"
local version="$2"
local lang="$3"
local requested="$version"
local tried="n"
local success="n"
local seconds="5"
@@ -1073,6 +1101,17 @@ downloadImage() {
fi
fi
if switchEdition version; then
desc=$(printVariant "$DETECTED" "" "Y")
web_desc=$(printVariant "$DETECTED" "")
if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then
desc+=" in $language"
fi
fi
if isESD "$version" "$lang"; then
if [[ "$tried" != "n" ]]; then
@@ -1122,7 +1161,7 @@ downloadImage() {
done
if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then
if fallbackEnglish "$iso" "$version" "$lang" "$desc" "$web_desc"; then
if fallbackEnglish "$iso" "$requested" "$lang" "$desc" "$web_desc"; then
return 0
fi
fi
+1 -1
View File
@@ -164,7 +164,7 @@ abortDuringSetup() {
gracefulShutdown() {
local sig="$1"
local pid="" code=0
local pid code
[[ $BASHPID != "$TRAP_PID" ]] && return
+19 -13
View File
@@ -24,20 +24,26 @@ configureNetwork() {
hostname="$UPLINK"
interfaces="$DEV"
return 0
fi
hostname="host.lan"
if isUserMode; then
interfaces="lo"
else
interfaces="$BRIDGE"
hostname="host.lan"
if isUserMode; then
interfaces="lo"
else
interfaces="$BRIDGE"
fi
if [ -n "${SAMBA_INTERFACE:-}" ]; then
interfaces+=",$SAMBA_INTERFACE"
fi
fi
if [ -n "${SAMBA_INTERFACE:-}" ]; then
interfaces+=",$SAMBA_INTERFACE"
fi
netbios="${hostname%%.*}"
netbios="${netbios:0:15}"
[ -z "$netbios" ] && netbios="host"
return 0
}
@@ -81,7 +87,7 @@ addShare() {
local name="$3"
local comment="$4"
local cfg="$5"
local owner=""
local owner
local tmp="/tmp/smb"
if [ ! -d "$dir" ]; then
@@ -145,7 +151,7 @@ writeConfig() {
if ! {
echo "[global]"
echo " server string = Dockur"
echo " netbios name = $hostname"
echo " netbios name = $netbios"
echo " workgroup = WORKGROUP"
echo " interfaces = $interfaces"
echo " bind interfaces only = yes"