mirror of
https://github.com/dockur/windows.git
synced 2026-07-27 21:42:36 +07:00
Compare commits
45 Commits
e4d79e1a17
...
bada80331d
| Author | SHA1 | Date | |
|---|---|---|---|
| bada80331d | |||
| c589e1be18 | |||
| 2ac9d71b32 | |||
| e7e637531e | |||
| b90ded928b | |||
| 0d0dd7be87 | |||
| 5b080ac6c8 | |||
| 6df58b5dc7 | |||
| 8929f7cdcd | |||
| aa6240ff99 | |||
| 3d3bab023d | |||
| 36d127d8cf | |||
| 2b7d7bf902 | |||
| 30d9858c7d | |||
| 09941ba0f6 | |||
| 828bdb1b29 | |||
| c64cf2313b | |||
| f45575c13f | |||
| 11b300149f | |||
| 605f31af72 | |||
| 4e35ead612 | |||
| 0a3bff5a7d | |||
| fdad5260cf | |||
| 0728b3e0a8 | |||
| 184ab1c481 | |||
| 4cf7dc005b | |||
| da7dd544b3 | |||
| 213245e5c9 | |||
| 240db47ae0 | |||
| 2ee0ae2e28 | |||
| bc17fdfe74 | |||
| 3d9ede8852 | |||
| 66d51a23c6 | |||
| 6bdfb06827 | |||
| ce1e7b877d | |||
| d1b3364471 | |||
| 4b5eb2c882 | |||
| fe36fe3ab8 | |||
| c64467596b | |||
| 28b5ee1f08 | |||
| 173b67b2af | |||
| b692649a4f | |||
| b721ba2320 | |||
| 6bfe2ff106 | |||
| c739e41e7e |
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+529
-301
File diff suppressed because it is too large
Load Diff
+1182
-327
File diff suppressed because it is too large
Load Diff
+112
-155
@@ -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
@@ -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
@@ -164,7 +164,7 @@ abortDuringSetup() {
|
||||
gracefulShutdown() {
|
||||
|
||||
local sig="$1"
|
||||
local pid="" code=0
|
||||
local pid code
|
||||
|
||||
[[ $BASHPID != "$TRAP_PID" ]] && return
|
||||
|
||||
|
||||
+19
-13
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user