mirror of
https://github.com/dockur/windows.git
synced 2026-08-24 15:48:59 +01:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| efe47da76d | |||
| 2fe4645685 | |||
| afa55b476c | |||
| 1e5d3c75a8 | |||
| 4c74370da0 | |||
| ae9fa8716b | |||
| 0d84fd35f5 | |||
| d68a489295 | |||
| c86067cb6e | |||
| 37f4908f22 | |||
| 09627c4e51 | |||
| f6e6a15b42 | |||
| eeaf64bdd9 | |||
| eb1befd90e | |||
| afb28c9234 | |||
| 2a116bf655 | |||
| 9af2409510 | |||
| 6bfe3b1adc | |||
| 2904a8d932 | |||
| e490d142ef | |||
| 2bf6ae55ab | |||
| a0a4520be6 | |||
| 003d7da5db | |||
| 1c2efa65df | |||
| 00fe722d4e | |||
| 603bd079fc | |||
| be032648e8 | |||
| 1d98f065dc | |||
| a0822d00a7 | |||
| 8713fa50e1 | |||
| e8028db237 | |||
| e4b910fba3 | |||
| 1066895aca | |||
| 39862b25b5 | |||
| a3461db9a8 | |||
| 019c70dbaa | |||
| ffec37e758 | |||
| e832e705f9 | |||
| db6b085ae2 | |||
| cf93c6d7f3 | |||
| afce7af300 | |||
| cfac963278 | |||
| 0d7e26adad | |||
| 9ef6f3c4ca | |||
| 5b9a376111 | |||
| a4ae486d83 | |||
| c9b12ba97d | |||
| 7e3e24780d | |||
| 433c83cab0 | |||
| 19264a42da | |||
| 33ae12677e | |||
| 133c3d3bc3 | |||
| 43be9024e9 |
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "Tiny11 Nano",
|
"name": "Windows ME",
|
||||||
"service": "windows",
|
"service": "windows",
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"VERSION": "nano11"
|
"VERSION": "me"
|
||||||
},
|
},
|
||||||
"forwardPorts": [8006],
|
"forwardPorts": [8006],
|
||||||
"portsAttributes": {
|
"portsAttributes": {
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "Windows 98",
|
||||||
|
"service": "windows",
|
||||||
|
"containerEnv": {
|
||||||
|
"VERSION": "98"
|
||||||
|
},
|
||||||
|
"forwardPorts": [8006],
|
||||||
|
"portsAttributes": {
|
||||||
|
"8006": {
|
||||||
|
"label": "Web",
|
||||||
|
"onAutoForward": "notify"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"otherPortsAttributes": {
|
||||||
|
"onAutoForward": "ignore"
|
||||||
|
},
|
||||||
|
"dockerComposeFile": "../codespaces.yml",
|
||||||
|
"initializeCommand": "docker system prune --all --force"
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "Windows 95",
|
||||||
|
"service": "windows",
|
||||||
|
"containerEnv": {
|
||||||
|
"VERSION": "95"
|
||||||
|
},
|
||||||
|
"forwardPorts": [8006],
|
||||||
|
"portsAttributes": {
|
||||||
|
"8006": {
|
||||||
|
"label": "Web",
|
||||||
|
"onAutoForward": "notify"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"otherPortsAttributes": {
|
||||||
|
"onAutoForward": "ignore"
|
||||||
|
},
|
||||||
|
"dockerComposeFile": "../codespaces.yml",
|
||||||
|
"initializeCommand": "docker system prune --all --force"
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "Reactos",
|
||||||
|
"service": "windows",
|
||||||
|
"containerEnv": {
|
||||||
|
"VERSION": "reactos"
|
||||||
|
},
|
||||||
|
"forwardPorts": [8006],
|
||||||
|
"portsAttributes": {
|
||||||
|
"8006": {
|
||||||
|
"label": "Web",
|
||||||
|
"onAutoForward": "notify"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"otherPortsAttributes": {
|
||||||
|
"onAutoForward": "ignore"
|
||||||
|
},
|
||||||
|
"dockerComposeFile": "../codespaces.yml",
|
||||||
|
"initializeCommand": "docker system prune --all --force"
|
||||||
|
}
|
||||||
@@ -73,6 +73,12 @@ on:
|
|||||||
default: false
|
default: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
|
tunnel_delay:
|
||||||
|
description: Automatically open the noVNC tunnel after this many seconds
|
||||||
|
required: false
|
||||||
|
default: 0
|
||||||
|
type: number
|
||||||
|
|
||||||
kill_on_failure:
|
kill_on_failure:
|
||||||
description: Stop the workflow when an installation failure is detected
|
description: Stop the workflow when an installation failure is detected
|
||||||
required: false
|
required: false
|
||||||
@@ -227,11 +233,12 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
CALLBACK: ${{ inputs.callback }}
|
CALLBACK: ${{ inputs.callback }}
|
||||||
|
VERSION: ${{ inputs.version }}
|
||||||
run: |
|
run: |
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
case "$CALLBACK" in
|
case "$CALLBACK" in
|
||||||
powershell | legacy)
|
powershell | legacy | basic)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unsupported guest script type: $CALLBACK"
|
echo "Unsupported guest script type: $CALLBACK"
|
||||||
@@ -249,6 +256,7 @@ jobs:
|
|||||||
printf '%s\n' "$token" > "$RUNNER_TEMP/data/validation.token"
|
printf '%s\n' "$token" > "$RUNNER_TEMP/data/validation.token"
|
||||||
printf '%s\n' "$token" > "$RUNNER_TEMP/oem/validation.token"
|
printf '%s\n' "$token" > "$RUNNER_TEMP/oem/validation.token"
|
||||||
|
|
||||||
|
if [[ "$CALLBACK" != "basic" ]]; then
|
||||||
cat > "$RUNNER_TEMP/oem/sync-log.bat" <<'BATCH'
|
cat > "$RUNNER_TEMP/oem/sync-log.bat" <<'BATCH'
|
||||||
@echo off
|
@echo off
|
||||||
setlocal
|
setlocal
|
||||||
@@ -327,6 +335,7 @@ jobs:
|
|||||||
|
|
||||||
shell.Run "cmd.exe /C echo VALIDATION_CALLBACK_FAILED^>COM1", 0, True
|
shell.Run "cmd.exe /C echo VALIDATION_CALLBACK_FAILED^>COM1", 0, True
|
||||||
VBSCRIPT
|
VBSCRIPT
|
||||||
|
fi
|
||||||
|
|
||||||
case "$CALLBACK" in
|
case "$CALLBACK" in
|
||||||
powershell)
|
powershell)
|
||||||
@@ -361,6 +370,12 @@ jobs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath "Z:\" -PathType Container)) {
|
||||||
|
throw "Mapped Z: drive is not available."
|
||||||
|
}
|
||||||
|
|
||||||
|
$driveZ = "ok"
|
||||||
|
|
||||||
$share = (
|
$share = (
|
||||||
Get-Content `
|
Get-Content `
|
||||||
-LiteralPath "\\host.lan\Data\validation.token" `
|
-LiteralPath "\\host.lan\Data\validation.token" `
|
||||||
@@ -423,6 +438,7 @@ jobs:
|
|||||||
version = [string]$windows.Version
|
version = [string]$windows.Version
|
||||||
build = [string]$windows.BuildNumber
|
build = [string]$windows.BuildNumber
|
||||||
platform = $platform
|
platform = $platform
|
||||||
|
drive_z = $driveZ
|
||||||
oem_file = $oemFile
|
oem_file = $oemFile
|
||||||
share = $share
|
share = $share
|
||||||
share_write = "ok"
|
share_write = "ok"
|
||||||
@@ -582,6 +598,15 @@ jobs:
|
|||||||
TestSharedFolder = "ok"
|
TestSharedFolder = "ok"
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
|
Function TestMappedDrive(filesystem)
|
||||||
|
If Not filesystem.DriveExists("Z:") Then
|
||||||
|
Err.Raise vbObjectError + 4, "TestMappedDrive", _
|
||||||
|
"Mapped Z: drive is not available."
|
||||||
|
End If
|
||||||
|
|
||||||
|
TestMappedDrive = "ok"
|
||||||
|
End Function
|
||||||
|
|
||||||
Function TestInternet()
|
Function TestInternet()
|
||||||
Dim request
|
Dim request
|
||||||
Dim response
|
Dim response
|
||||||
@@ -639,6 +664,7 @@ jobs:
|
|||||||
Dim oemFile
|
Dim oemFile
|
||||||
Dim share
|
Dim share
|
||||||
Dim shareWrite
|
Dim shareWrite
|
||||||
|
Dim driveZ
|
||||||
Dim internet
|
Dim internet
|
||||||
|
|
||||||
Dim json
|
Dim json
|
||||||
@@ -677,6 +703,7 @@ jobs:
|
|||||||
oemFile = ReadTextFile(filesystem, "C:\OEM\validation.token")
|
oemFile = ReadTextFile(filesystem, "C:\OEM\validation.token")
|
||||||
share = ReadTextFile(filesystem, "\\host.lan\Data\validation.token")
|
share = ReadTextFile(filesystem, "\\host.lan\Data\validation.token")
|
||||||
shareWrite = TestSharedFolder(filesystem, token)
|
shareWrite = TestSharedFolder(filesystem, token)
|
||||||
|
driveZ = TestMappedDrive(filesystem)
|
||||||
internet = TestInternet()
|
internet = TestInternet()
|
||||||
End If
|
End If
|
||||||
|
|
||||||
@@ -692,6 +719,7 @@ jobs:
|
|||||||
"""oem_file"":""" & EscapeJson(oemFile) & """," & _
|
"""oem_file"":""" & EscapeJson(oemFile) & """," & _
|
||||||
"""share"":""" & EscapeJson(share) & """," & _
|
"""share"":""" & EscapeJson(share) & """," & _
|
||||||
"""share_write"":""" & EscapeJson(shareWrite) & """," & _
|
"""share_write"":""" & EscapeJson(shareWrite) & """," & _
|
||||||
|
"""drive_z"":""" & EscapeJson(driveZ) & """," & _
|
||||||
"""internet"":""" & EscapeJson(internet) & """" & _
|
"""internet"":""" & EscapeJson(internet) & """" & _
|
||||||
"}"
|
"}"
|
||||||
|
|
||||||
@@ -764,6 +792,42 @@ jobs:
|
|||||||
exit /B %result%
|
exit /B %result%
|
||||||
EOF
|
EOF
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
basic)
|
||||||
|
case "${VERSION,,}" in
|
||||||
|
95) share_host="Host" ;;
|
||||||
|
*) share_host="host.lan" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
sed "s|@@SHARE_HOST@@|$share_host|g" > "$RUNNER_TEMP/oem/install.bat" <<'BATCH'
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
:retry
|
||||||
|
if not exist \\@@SHARE_HOST@@\Data\validation.token goto wait
|
||||||
|
if not exist Z:\validation.token goto wait
|
||||||
|
|
||||||
|
echo TOKEN> C:\OEM\validation.result
|
||||||
|
type C:\OEM\validation.token >> C:\OEM\validation.result
|
||||||
|
echo SHARE>> C:\OEM\validation.result
|
||||||
|
type \\@@SHARE_HOST@@\Data\validation.token >> C:\OEM\validation.result
|
||||||
|
echo DRIVE_Z>> C:\OEM\validation.result
|
||||||
|
echo ok>> C:\OEM\validation.result
|
||||||
|
echo VERSION>> C:\OEM\validation.result
|
||||||
|
ver >> C:\OEM\validation.result
|
||||||
|
|
||||||
|
if exist \\@@SHARE_HOST@@\Data\validation.result del \\@@SHARE_HOST@@\Data\validation.result >nul
|
||||||
|
copy C:\OEM\validation.result \\@@SHARE_HOST@@\Data\validation.result >nul
|
||||||
|
if errorlevel 1 goto wait
|
||||||
|
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:wait
|
||||||
|
ping 127.0.0.1 -n 6 >nul
|
||||||
|
goto retry
|
||||||
|
|
||||||
|
:end
|
||||||
|
BATCH
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo "token=$token" >> "$GITHUB_OUTPUT"
|
echo "token=$token" >> "$GITHUB_OUTPUT"
|
||||||
@@ -890,6 +954,9 @@ jobs:
|
|||||||
- name: Install and validate Windows
|
- name: Install and validate Windows
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
|
CALLBACK: ${{ inputs.callback }}
|
||||||
|
ENABLE_TUNNEL: ${{ inputs.enable_tunnel }}
|
||||||
|
TUNNEL_DELAY: ${{ inputs.tunnel_delay }}
|
||||||
KILL_ON_FAILURE: ${{ inputs.kill_on_failure }}
|
KILL_ON_FAILURE: ${{ inputs.kill_on_failure }}
|
||||||
INSTALL_TIMEOUT: ${{ inputs.install_timeout }}
|
INSTALL_TIMEOUT: ${{ inputs.install_timeout }}
|
||||||
REBOOT_TIMEOUT: ${{ inputs.reboot_timeout }}
|
REBOOT_TIMEOUT: ${{ inputs.reboot_timeout }}
|
||||||
@@ -901,6 +968,7 @@ jobs:
|
|||||||
EXPECTED_PLATFORM: ${{ inputs.platform }}
|
EXPECTED_PLATFORM: ${{ inputs.platform }}
|
||||||
MINIMUM_BUILD: ${{ inputs.minimum_build }}
|
MINIMUM_BUILD: ${{ inputs.minimum_build }}
|
||||||
DISPLAY_NAME: ${{ inputs.name }}
|
DISPLAY_NAME: ${{ inputs.name }}
|
||||||
|
VERSION: ${{ inputs.version }}
|
||||||
run: |
|
run: |
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
@@ -954,8 +1022,82 @@ jobs:
|
|||||||
) &
|
) &
|
||||||
|
|
||||||
guest_logs_pid="$!"
|
guest_logs_pid="$!"
|
||||||
|
tunnel_delay_pid=""
|
||||||
|
|
||||||
|
start_delayed_tunnel() {
|
||||||
|
local state
|
||||||
|
local novnc_url
|
||||||
|
|
||||||
|
sleep "$TUNNEL_DELAY"
|
||||||
|
|
||||||
|
state="$(
|
||||||
|
docker inspect \
|
||||||
|
--format '{{.State.Status}}' \
|
||||||
|
"$CONTAINER" 2>/dev/null || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ "$state" != "running" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
echo "Installation is still running after $((TUNNEL_DELAY / 60)) minutes."
|
||||||
|
echo "Starting temporary noVNC tunnel..."
|
||||||
|
|
||||||
|
if docker run --detach \
|
||||||
|
--name "$TUNNEL" \
|
||||||
|
--network "container:$CONTAINER" \
|
||||||
|
cloudflare/cloudflared:latest \
|
||||||
|
tunnel \
|
||||||
|
--no-autoupdate \
|
||||||
|
--url http://127.0.0.1:8006 > /dev/null 2>/dev/null; then
|
||||||
|
novnc_url=""
|
||||||
|
|
||||||
|
for _ in {1..30}; do
|
||||||
|
novnc_url="$(
|
||||||
|
docker logs "$TUNNEL" 2>&1 |
|
||||||
|
grep -Eo 'https://[-a-z0-9]+\.trycloudflare\.com' |
|
||||||
|
tail -n 1 || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
[ -n "$novnc_url" ] && break
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$novnc_url" ]; then
|
||||||
|
echo
|
||||||
|
echo "::notice title=noVNC viewer::$novnc_url"
|
||||||
|
echo "noVNC viewer: $novnc_url"
|
||||||
|
echo "Warning: this temporary URL is publicly accessible."
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "### noVNC viewer"
|
||||||
|
echo
|
||||||
|
echo "[$novnc_url]($novnc_url)"
|
||||||
|
echo
|
||||||
|
echo "> This temporary URL is publicly accessible while the job is running."
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
else
|
||||||
|
echo "::warning::Failed to obtain a noVNC tunnel URL."
|
||||||
|
docker logs "$TUNNEL" 2>&1 || true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "::warning::Failed to start the noVNC tunnel."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$ENABLE_TUNNEL" != "true" ]] && (( TUNNEL_DELAY > 0 )); then
|
||||||
|
start_delayed_tunnel &
|
||||||
|
tunnel_delay_pid="$!"
|
||||||
|
fi
|
||||||
|
|
||||||
stop_logs() {
|
stop_logs() {
|
||||||
|
if [[ -n "$tunnel_delay_pid" ]]; then
|
||||||
|
kill "$tunnel_delay_pid" 2>/dev/null || true
|
||||||
|
wait "$tunnel_delay_pid" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
kill "$logs_pid" "$guest_logs_pid" 2>/dev/null || true
|
kill "$logs_pid" "$guest_logs_pid" 2>/dev/null || true
|
||||||
wait "$logs_pid" "$guest_logs_pid" 2>/dev/null || true
|
wait "$logs_pid" "$guest_logs_pid" 2>/dev/null || true
|
||||||
print_guest_log
|
print_guest_log
|
||||||
@@ -975,18 +1117,68 @@ jobs:
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Automatic termination is disabled by kill_on_failure."
|
echo "Automatic termination is disabled by kill_on_failure."
|
||||||
echo "The container and noVNC tunnel will remain available."
|
echo "The container will remain available for debugging."
|
||||||
echo "::warning title=Failure detected::$message"
|
echo "::warning title=Failure detected::$message"
|
||||||
failure_checks_disabled=1
|
failure_checks_disabled=1
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_rdp_port() {
|
||||||
|
local container_ip
|
||||||
|
local attempt
|
||||||
|
|
||||||
|
container_ip="$(
|
||||||
|
docker inspect \
|
||||||
|
--format '{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' \
|
||||||
|
"$CONTAINER" 2>/dev/null |
|
||||||
|
head -n 1 || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ -z "$container_ip" ]]; then
|
||||||
|
echo "Could not determine the Windows container IP address."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Checking TCP port 3389 at $container_ip..."
|
||||||
|
|
||||||
|
for attempt in {1..30}; do
|
||||||
|
if timeout 2 bash -c \
|
||||||
|
"exec 3<>/dev/tcp/$container_ip/3389; exec 3>&-; exec 3<&-" \
|
||||||
|
2>/dev/null; then
|
||||||
|
echo "TCP port 3389 is open."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
case "${VERSION,,}" in
|
||||||
|
95 | 98 | me)
|
||||||
|
echo "::warning::TCP port 3389 is not open for $DISPLAY_NAME; this is allowed."
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "TCP port 3389 is not open for $DISPLAY_NAME."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
deadline=$((SECONDS + INSTALL_TIMEOUT))
|
deadline=$((SECONDS + INSTALL_TIMEOUT))
|
||||||
reboot_timeout="$REBOOT_TIMEOUT"
|
reboot_timeout="$REBOOT_TIMEOUT"
|
||||||
minimum_reboots="$MINIMUM_REBOOTS"
|
minimum_reboots="$MINIMUM_REBOOTS"
|
||||||
boot_loop_limit="$BOOT_LOOP_LIMIT"
|
boot_loop_limit="$BOOT_LOOP_LIMIT"
|
||||||
first_bios_start=-1
|
first_bios_start=-1
|
||||||
|
|
||||||
|
version_lower="${VERSION,,}"
|
||||||
|
|
||||||
|
case "$version_lower" in
|
||||||
|
95 | 98 | me)
|
||||||
|
reboot_timeout=$((REBOOT_TIMEOUT * 2))
|
||||||
|
echo "Extended first reboot timeout to $((reboot_timeout / 60)) minutes for $DISPLAY_NAME."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
while (( SECONDS < deadline )); do
|
while (( SECONDS < deadline )); do
|
||||||
state="$(
|
state="$(
|
||||||
docker inspect \
|
docker inspect \
|
||||||
@@ -1023,7 +1215,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Automatic termination is disabled by kill_on_failure."
|
echo "Automatic termination is disabled by kill_on_failure."
|
||||||
echo "The container and noVNC tunnel will remain available."
|
echo "The container will remain available for debugging."
|
||||||
echo "::warning title=Failure detected::The guest validation callback failed."
|
echo "::warning title=Failure detected::The guest validation callback failed."
|
||||||
failure_checks_disabled=1
|
failure_checks_disabled=1
|
||||||
fi
|
fi
|
||||||
@@ -1108,7 +1300,8 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if (( bios_starts >= boot_loop_limit )) &&
|
if (( failure_checks_disabled == 0 &&
|
||||||
|
bios_starts >= boot_loop_limit )) &&
|
||||||
(( hard_disk_boots >= boot_loop_limit ||
|
(( hard_disk_boots >= boot_loop_limit ||
|
||||||
dvd_boots >= boot_loop_limit ||
|
dvd_boots >= boot_loop_limit ||
|
||||||
not_bootable_disk >= boot_loop_limit ||
|
not_bootable_disk >= boot_loop_limit ||
|
||||||
@@ -1127,7 +1320,118 @@ jobs:
|
|||||||
echo "No-bootable-device failures: $no_bootable_device"
|
echo "No-bootable-device failures: $no_bootable_device"
|
||||||
echo "BOOTMGR failures: $bootmgr_missing"
|
echo "BOOTMGR failures: $bootmgr_missing"
|
||||||
|
|
||||||
exit 1
|
if ! handle_failure "Detected a repeated BIOS boot loop."; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
basic_result="$RUNNER_TEMP/data/validation.result"
|
||||||
|
|
||||||
|
if [[ "$CALLBACK" == "basic" && -s "$basic_result" ]]; then
|
||||||
|
basic_response="$(tr -d '\r' < "$basic_result")"
|
||||||
|
|
||||||
|
oem_file="$(
|
||||||
|
awk '$0 == "TOKEN" { getline; print; exit }' <<< "$basic_response"
|
||||||
|
)"
|
||||||
|
|
||||||
|
share="$(
|
||||||
|
awk '$0 == "SHARE" { getline; print; exit }' <<< "$basic_response"
|
||||||
|
)"
|
||||||
|
|
||||||
|
drive_z="$(
|
||||||
|
awk '$0 == "DRIVE_Z" { getline; print; exit }' <<< "$basic_response"
|
||||||
|
)"
|
||||||
|
|
||||||
|
version="$(
|
||||||
|
awk '
|
||||||
|
$0 == "VERSION" { found = 1; next }
|
||||||
|
found && NF { print; exit }
|
||||||
|
' <<< "$basic_response"
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ -z "$oem_file" || -z "$share" || -z "$drive_z" || -z "$version" ]] ||
|
||||||
|
! grep -Eq '[0-9]+\.[0-9]+\.[0-9]+' <<< "$version"; then
|
||||||
|
sleep 1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
stop_logs
|
||||||
|
trap - EXIT
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
echo "Received response:"
|
||||||
|
printf '%s\n' "$basic_response"
|
||||||
|
|
||||||
|
if [[ "$oem_file" != "$EXPECTED_TOKEN" ]]; then
|
||||||
|
echo "Failed to read C:\\OEM\\validation.token."
|
||||||
|
echo "Expected contents:"
|
||||||
|
echo " $EXPECTED_TOKEN"
|
||||||
|
echo "Received:"
|
||||||
|
echo " ${oem_file:-empty}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$share" != "$EXPECTED_TOKEN" ]]; then
|
||||||
|
echo "Failed to read \\\\host.lan\\Data\\validation.token."
|
||||||
|
echo "Expected contents:"
|
||||||
|
echo " $EXPECTED_TOKEN"
|
||||||
|
echo "Received:"
|
||||||
|
echo " ${share:-empty}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$drive_z" != "ok" ]]; then
|
||||||
|
echo "The mapped Z: drive test did not succeed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
normalized_caption="${version//\(R\)/}"
|
||||||
|
normalized_expected_caption="${EXPECTED_CAPTION//\(R\)/}"
|
||||||
|
|
||||||
|
if [[ "$normalized_caption" != *"$normalized_expected_caption"* ]]; then
|
||||||
|
echo "Expected caption containing:"
|
||||||
|
echo " $EXPECTED_CAPTION"
|
||||||
|
echo "Received:"
|
||||||
|
echo " $version"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
version_number="$(
|
||||||
|
grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' <<< "$version" |
|
||||||
|
head -n 1 || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ ! "$version_number" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "Unexpected Windows version: $version"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
build="${version_number##*.}"
|
||||||
|
|
||||||
|
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 ! check_rdp_port; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "$DISPLAY_NAME installed successfully."
|
||||||
|
echo "Version: $version_number"
|
||||||
|
echo "Build: $build"
|
||||||
|
echo "OEM files: copied successfully"
|
||||||
|
echo "Shared folder: readable and writable"
|
||||||
|
echo "Mapped Z: drive: available"
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
response="$(
|
response="$(
|
||||||
@@ -1160,6 +1464,7 @@ jobs:
|
|||||||
oem_file="$(jq -r '.oem_file // empty' <<< "$response")"
|
oem_file="$(jq -r '.oem_file // empty' <<< "$response")"
|
||||||
share="$(jq -r '.share // empty' <<< "$response")"
|
share="$(jq -r '.share // empty' <<< "$response")"
|
||||||
share_write="$(jq -r '.share_write // empty' <<< "$response")"
|
share_write="$(jq -r '.share_write // empty' <<< "$response")"
|
||||||
|
drive_z="$(jq -r '.drive_z // empty' <<< "$response")"
|
||||||
internet="$(jq -r '.internet // empty' <<< "$response")"
|
internet="$(jq -r '.internet // empty' <<< "$response")"
|
||||||
|
|
||||||
if [[ "$token" != "$EXPECTED_TOKEN" ]]; then
|
if [[ "$token" != "$EXPECTED_TOKEN" ]]; then
|
||||||
@@ -1190,6 +1495,11 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "$drive_z" != "ok" ]]; then
|
||||||
|
echo "The mapped Z: drive test did not succeed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$internet" != "ok" ]]; then
|
if [[ "$internet" != "ok" ]]; then
|
||||||
echo "The guest internet connection test did not succeed."
|
echo "The guest internet connection test did not succeed."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -1240,6 +1550,10 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! check_rdp_port; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "$DISPLAY_NAME installed successfully."
|
echo "$DISPLAY_NAME installed successfully."
|
||||||
echo "Version: $version"
|
echo "Version: $version"
|
||||||
@@ -1247,6 +1561,7 @@ jobs:
|
|||||||
echo "Platform: $platform"
|
echo "Platform: $platform"
|
||||||
echo "OEM files: copied successfully"
|
echo "OEM files: copied successfully"
|
||||||
echo "Shared folder: readable and writable"
|
echo "Shared folder: readable and writable"
|
||||||
|
echo "Mapped Z: drive: available"
|
||||||
echo "Internet connection: accessible"
|
echo "Internet connection: accessible"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -52,9 +52,10 @@ jobs:
|
|||||||
version: ${{ inputs.version }}
|
version: ${{ inputs.version }}
|
||||||
callback: ${{ inputs.callback }}
|
callback: ${{ inputs.callback }}
|
||||||
enable_tunnel: false
|
enable_tunnel: false
|
||||||
|
tunnel_delay: 1800
|
||||||
kill_on_failure: true
|
kill_on_failure: true
|
||||||
install_timeout: 9000
|
install_timeout: 9000
|
||||||
reboot_timeout: 1800
|
reboot_timeout: 18000
|
||||||
minimum_reboots: 1
|
minimum_reboots: 1
|
||||||
boot_loop_limit: 10
|
boot_loop_limit: 10
|
||||||
expected_caption: ${{ inputs.expected_caption }}
|
expected_caption: ${{ inputs.expected_caption }}
|
||||||
|
|||||||
@@ -206,6 +206,39 @@ jobs:
|
|||||||
minimum_build: ${{ matrix.minimum_build }}
|
minimum_build: ${{ matrix.minimum_build }}
|
||||||
platform: ${{ matrix.platform }}
|
platform: ${{ matrix.platform }}
|
||||||
|
|
||||||
|
win9x:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: Windows 95
|
||||||
|
version: "95"
|
||||||
|
expected_caption: Windows 95
|
||||||
|
minimum_build: 950
|
||||||
|
platform: x86
|
||||||
|
|
||||||
|
- name: Windows 98
|
||||||
|
version: "98"
|
||||||
|
expected_caption: Windows 98
|
||||||
|
minimum_build: 2222
|
||||||
|
platform: x86
|
||||||
|
|
||||||
|
- name: Windows ME
|
||||||
|
version: "me"
|
||||||
|
expected_caption: Windows Millennium
|
||||||
|
minimum_build: 3000
|
||||||
|
platform: x86
|
||||||
|
|
||||||
|
name: ${{ matrix.name }}
|
||||||
|
uses: ./.github/workflows/settings.yml
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.name }}
|
||||||
|
version: ${{ matrix.version }}
|
||||||
|
callback: basic
|
||||||
|
expected_caption: ${{ matrix.expected_caption }}
|
||||||
|
minimum_build: ${{ matrix.minimum_build }}
|
||||||
|
platform: ${{ matrix.platform }}
|
||||||
|
|
||||||
tiny:
|
tiny:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|||||||
+5
-7
@@ -3,13 +3,13 @@
|
|||||||
ARG VERSION_ARG="latest"
|
ARG VERSION_ARG="latest"
|
||||||
FROM scratch AS build-amd64
|
FROM scratch AS build-amd64
|
||||||
|
|
||||||
COPY --from=qemux/qemu:7.44 / /
|
COPY --from=qemux/qemu:7.48 / /
|
||||||
|
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
|
|
||||||
ARG VERSION_UDF="1.2.0"
|
ARG VERSION_UDF="1.2.0"
|
||||||
ARG VERSION_WSDD="1.26"
|
ARG VERSION_WSDD="1.27"
|
||||||
ARG VERSION_VIRTIO="1.9.58"
|
ARG VERSION_VIRTIO="1.9.60"
|
||||||
ARG VERSION_BLINTER="1.0.112"
|
ARG VERSION_BLINTER="1.0.112"
|
||||||
|
|
||||||
ARG DEBCONF_NOWARNINGS="yes"
|
ARG DEBCONF_NOWARNINGS="yes"
|
||||||
@@ -21,6 +21,7 @@ RUN <<EOF
|
|||||||
|
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get --no-install-recommends -y install \
|
apt-get --no-install-recommends -y install \
|
||||||
|
gcab \
|
||||||
samba \
|
samba \
|
||||||
mtools \
|
mtools \
|
||||||
wimtools \
|
wimtools \
|
||||||
@@ -32,10 +33,7 @@ RUN <<EOF
|
|||||||
libarchive-tools
|
libarchive-tools
|
||||||
|
|
||||||
# Install Blinter
|
# Install Blinter
|
||||||
python3 -m pip install \
|
python3 -m pip install --break-system-packages --root-user-action=ignore --no-cache-dir "Blinter==${VERSION_BLINTER}"
|
||||||
--break-system-packages \
|
|
||||||
--no-cache-dir \
|
|
||||||
"Blinter==${VERSION_BLINTER}"
|
|
||||||
|
|
||||||
# Install wsddn package
|
# Install wsddn package
|
||||||
wget "https://github.com/gershnik/wsdd-native/releases/download/v${VERSION_WSDD}/wsddn_${VERSION_WSDD}_${TARGETARCH}.deb" -O /tmp/wsddn.deb -q --timeout=10
|
wget "https://github.com/gershnik/wsdd-native/releases/download/v${VERSION_WSDD}/wsddn_${VERSION_WSDD}_${TARGETARCH}.deb" -O /tmp/wsddn.deb -q --timeout=10
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ if exist "%SETUP_COMPLETE%" exit /b 0
|
|||||||
|
|
||||||
type nul > "%SETUP_STARTED%"
|
type nul > "%SETUP_STARTED%"
|
||||||
|
|
||||||
|
rem Disable Shutdown Event Tracker.
|
||||||
|
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" /v "ShutdownReasonOn" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
rem Allow guest access to network shares.
|
rem Allow guest access to network shares.
|
||||||
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ if exist "%SETUP_COMPLETE%" exit /b 0
|
|||||||
|
|
||||||
type nul > "%SETUP_STARTED%"
|
type nul > "%SETUP_STARTED%"
|
||||||
|
|
||||||
|
rem Disable Shutdown Event Tracker.
|
||||||
|
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" /v "ShutdownReasonOn" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
rem Allow guest access to network shares.
|
rem Allow guest access to network shares.
|
||||||
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ if exist "%SETUP_COMPLETE%" exit /b 0
|
|||||||
|
|
||||||
type nul > "%SETUP_STARTED%"
|
type nul > "%SETUP_STARTED%"
|
||||||
|
|
||||||
|
rem Disable Shutdown Event Tracker.
|
||||||
|
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" /v "ShutdownReasonOn" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
rem Allow guest access to network shares.
|
rem Allow guest access to network shares.
|
||||||
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ if exist "%SETUP_COMPLETE%" exit /b 0
|
|||||||
|
|
||||||
type nul > "%SETUP_STARTED%"
|
type nul > "%SETUP_STARTED%"
|
||||||
|
|
||||||
|
rem Disable Shutdown Event Tracker.
|
||||||
|
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" /v "ShutdownReasonOn" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
rem Allow guest access to network shares.
|
rem Allow guest access to network shares.
|
||||||
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ if exist "%SETUP_COMPLETE%" exit /b 0
|
|||||||
|
|
||||||
type nul > "%SETUP_STARTED%"
|
type nul > "%SETUP_STARTED%"
|
||||||
|
|
||||||
|
rem Disable Shutdown Event Tracker.
|
||||||
|
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" /v "ShutdownReasonOn" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
rem Allow guest access to network shares.
|
rem Allow guest access to network shares.
|
||||||
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ if exist "%SETUP_COMPLETE%" exit /b 0
|
|||||||
|
|
||||||
type nul > "%SETUP_STARTED%"
|
type nul > "%SETUP_STARTED%"
|
||||||
|
|
||||||
|
rem Disable Shutdown Event Tracker.
|
||||||
|
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" /v "ShutdownReasonOn" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
rem Allow guest access to network shares.
|
rem Allow guest access to network shares.
|
||||||
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ if exist "%SETUP_COMPLETE%" exit /b 0
|
|||||||
|
|
||||||
type nul > "%SETUP_STARTED%"
|
type nul > "%SETUP_STARTED%"
|
||||||
|
|
||||||
|
rem Disable Shutdown Event Tracker.
|
||||||
|
reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" /v "ShutdownReasonOn" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
rem Allow guest access to network shares.
|
rem Allow guest access to network shares.
|
||||||
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Y
|
|||||||
rem Enable File Sharing.
|
rem Enable File Sharing.
|
||||||
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
||||||
|
|
||||||
|
rem Install the VirtIO Balloon service once.
|
||||||
|
sc.exe query BalloonService >nul 2>&1
|
||||||
|
if errorlevel 1 "%SystemRoot%\Drivers\Balloon\blnsvr.exe" -i
|
||||||
|
|
||||||
rem BEGIN PRODUCT_KEY
|
rem BEGIN PRODUCT_KEY
|
||||||
rem Install the product key without activating Windows immediately.
|
rem Install the product key without activating Windows immediately.
|
||||||
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Y
|
|||||||
rem Enable File Sharing.
|
rem Enable File Sharing.
|
||||||
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
||||||
|
|
||||||
|
rem Install the VirtIO Balloon service once.
|
||||||
|
sc.exe query BalloonService >nul 2>&1
|
||||||
|
if errorlevel 1 "%SystemRoot%\Drivers\Balloon\blnsvr.exe" -i
|
||||||
|
|
||||||
rem BEGIN PRODUCT_KEY
|
rem BEGIN PRODUCT_KEY
|
||||||
rem Install the product key without activating Windows immediately.
|
rem Install the product key without activating Windows immediately.
|
||||||
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Y
|
|||||||
rem Enable File Sharing.
|
rem Enable File Sharing.
|
||||||
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
||||||
|
|
||||||
|
rem Install the VirtIO Balloon service once.
|
||||||
|
sc.exe query BalloonService >nul 2>&1
|
||||||
|
if errorlevel 1 "%SystemRoot%\Drivers\Balloon\blnsvr.exe" -i
|
||||||
|
|
||||||
rem BEGIN PRODUCT_KEY
|
rem BEGIN PRODUCT_KEY
|
||||||
rem Install the product key without activating Windows immediately.
|
rem Install the product key without activating Windows immediately.
|
||||||
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Y
|
|||||||
rem Enable File Sharing.
|
rem Enable File Sharing.
|
||||||
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
||||||
|
|
||||||
|
rem Install the VirtIO Balloon service once.
|
||||||
|
sc.exe query BalloonService >nul 2>&1
|
||||||
|
if errorlevel 1 "%SystemRoot%\Drivers\Balloon\blnsvr.exe" -i
|
||||||
|
|
||||||
rem BEGIN PRODUCT_KEY
|
rem BEGIN PRODUCT_KEY
|
||||||
rem Install the product key without activating Windows immediately.
|
rem Install the product key without activating Windows immediately.
|
||||||
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Y
|
|||||||
rem Enable File Sharing.
|
rem Enable File Sharing.
|
||||||
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
||||||
|
|
||||||
|
rem Install the VirtIO Balloon service once.
|
||||||
|
sc.exe query BalloonService >nul 2>&1
|
||||||
|
if errorlevel 1 "%SystemRoot%\Drivers\Balloon\blnsvr.exe" -i
|
||||||
|
|
||||||
rem BEGIN PRODUCT_KEY
|
rem BEGIN PRODUCT_KEY
|
||||||
rem Install the product key without activating Windows immediately.
|
rem Install the product key without activating Windows immediately.
|
||||||
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Y
|
|||||||
rem Enable File Sharing.
|
rem Enable File Sharing.
|
||||||
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes
|
||||||
|
|
||||||
|
rem Install the VirtIO Balloon service once.
|
||||||
|
sc.exe query BalloonService >nul 2>&1
|
||||||
|
if errorlevel 1 "%SystemRoot%\Drivers\Balloon\blnsvr.exe" -i
|
||||||
|
|
||||||
rem BEGIN PRODUCT_KEY
|
rem BEGIN PRODUCT_KEY
|
||||||
rem Install the product key without activating Windows immediately.
|
rem Install the product key without activating Windows immediately.
|
||||||
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
cscript.exe //B //Nologo "%SystemRoot%\System32\slmgr.vbs" /ipk "XXX"
|
||||||
|
|||||||
+9
-6
@@ -41,7 +41,7 @@ An empty default means the variable is unset and its value is determined automat
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `DISK_SIZE` | `64G` | Size of the primary disk. |
|
| `DISK_SIZE` | `64G` | Size of the primary disk. |
|
||||||
| `DISK_FMT` | `raw` | Disk image format: `raw` or `qcow2`. |
|
| `DISK_FMT` | `raw` | Disk image format: `raw` or `qcow2`. |
|
||||||
| `DISK_TYPE` | `scsi` | Disk device type, such as `sata`, `scsi`, `nvme`, or `blk`. |
|
| `DISK_TYPE` | `scsi` | Disk device type, such as `ide`, `scsi`, or `blk`. |
|
||||||
| `DISK_CACHE` | `none` | Disk cache mode, such as `none` or `writeback`. |
|
| `DISK_CACHE` | `none` | Disk cache mode, such as `none` or `writeback`. |
|
||||||
| `DISK_IO` | `native` | Disk I/O mode, such as `native`, `threads`, or `io_uring`. |
|
| `DISK_IO` | `native` | Disk I/O mode, such as `native`, `threads`, or `io_uring`. |
|
||||||
| `DISK_DISCARD` | `unmap` | Discard/TRIM mode for the primary disk. |
|
| `DISK_DISCARD` | `unmap` | Discard/TRIM mode for the primary disk. |
|
||||||
@@ -79,11 +79,10 @@ An empty default means the variable is unset and its value is determined automat
|
|||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `DISPLAY` | `web` | Display backend, such as `web`, `vnc`, `disabled`, or `none`. |
|
| `DISPLAY` | `web` | Display backend, such as `web`, `vnc`, `disabled`, or `none`. |
|
||||||
| `LOSSY` | `N` | Enables lossy VNC compression to reduce bandwidth usage. |
|
|
||||||
| `VGA` | `virtio` | QEMU video adapter model. |
|
| `VGA` | `virtio` | QEMU video adapter model. |
|
||||||
| `WIDTH` | `1280` | Display width configured in Windows. |
|
| `WIDTH` | `1280` | Display width configured in Windows. |
|
||||||
| `HEIGHT` | `720` | Display height configured in Windows. |
|
| `HEIGHT` | `720` | Display height configured in Windows. |
|
||||||
| `GPU` | `N` | Enables experimental Intel iGPU acceleration. |
|
| `GPU` | `N` | Enables experimental GPU acceleration. |
|
||||||
| `RENDERNODE` | `/dev/dri/renderD128` | Render node used for GPU acceleration. |
|
| `RENDERNODE` | `/dev/dri/renderD128` | Render node used for GPU acceleration. |
|
||||||
|
|
||||||
## 🌍 Web UI
|
## 🌍 Web UI
|
||||||
@@ -93,8 +92,8 @@ An empty default means the variable is unset and its value is determined automat
|
|||||||
| `WEB` | `Y` | Enables the web interface. |
|
| `WEB` | `Y` | Enables the web interface. |
|
||||||
| `WEB_PORT` | `8006` | Port for the web interface. |
|
| `WEB_PORT` | `8006` | Port for the web interface. |
|
||||||
| `VNC_PORT` | `5900` | Port for the VNC server. |
|
| `VNC_PORT` | `5900` | Port for the VNC server. |
|
||||||
|
| `LOSSY` | `N` | Enables lossy VNC compression to reduce bandwidth usage. |
|
||||||
| `AUDIO` | `N` | Streams guest audio to the web viewer. |
|
| `AUDIO` | `N` | Streams guest audio to the web viewer. |
|
||||||
| `SOUND` | `intel-hda` | QEMU audio device used by the web viewer. |
|
|
||||||
| `PROTECT` | `N` | Enables password protection for the web interface. |
|
| `PROTECT` | `N` | Enables password protection for the web interface. |
|
||||||
|
|
||||||
## 📁 File Sharing
|
## 📁 File Sharing
|
||||||
@@ -112,9 +111,12 @@ An empty default means the variable is unset and its value is determined automat
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `MACHINE` | `q35` | QEMU machine type. |
|
| `MACHINE` | `q35` | QEMU machine type. |
|
||||||
| `PCI_BUS` | `pcie.0` | Overrides the PCI bus used for attached devices. |
|
| `PCI_BUS` | `pcie.0` | Overrides the PCI bus used for attached devices. |
|
||||||
|
| `RNG` | `Y` | Adds the Virtio RNG device to the machine. |
|
||||||
| `UUID` | | UUID assigned to Windows. |
|
| `UUID` | | UUID assigned to Windows. |
|
||||||
| `HPET` | `off` | QEMU HPET timer setting. |
|
| `HPET` | `off` | HPET timer setting. |
|
||||||
| `VMPORT` | `off` | QEMU VMware port setting. |
|
| `VMPORT` | `off` | VMware port setting. |
|
||||||
|
| `MOUSE` | `usb-tablet` | Pointing device used by the machine. |
|
||||||
|
| `SOUND` | `intel-hda` | Audio device used when `AUDIO=Y`. |
|
||||||
| `SM_BIOS` | | Additional arguments passed to QEMU’s `-smbios` option. |
|
| `SM_BIOS` | | Additional arguments passed to QEMU’s `-smbios` option. |
|
||||||
| `ARGUMENTS` | | Additional raw arguments appended to the QEMU command line. |
|
| `ARGUMENTS` | | Additional raw arguments appended to the QEMU command line. |
|
||||||
|
|
||||||
@@ -177,3 +179,4 @@ Also see [Dynamic memory allocation](https://github.com/qemus/qemu/blob/master/d
|
|||||||
| `LOG` | `N` | Saves all output from `install.bat` to `C:\OEM\install.log` for troubleshooting. |
|
| `LOG` | `N` | Saves all output from `install.bat` to `C:\OEM\install.log` for troubleshooting. |
|
||||||
| `SERIAL` | `mon:stdio` | QEMU serial device configuration. |
|
| `SERIAL` | `mon:stdio` | QEMU serial device configuration. |
|
||||||
| `MONITOR` | | QEMU monitor configuration. |
|
| `MONITOR` | | QEMU monitor configuration. |
|
||||||
|
| `QMP` | | QEMU Machine Protocol configuration. |
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ For a complete graphical desktop experience, see [WinBoat](https://winboat.app),
|
|||||||
| `vu` | Windows Vista Ultimate | 3.0 GB |
|
| `vu` | Windows Vista Ultimate | 3.0 GB |
|
||||||
| `xp` | Windows XP Professional | 0.6 GB |
|
| `xp` | Windows XP Professional | 0.6 GB |
|
||||||
| `2k` | Windows 2000 Professional | 0.4 GB |
|
| `2k` | Windows 2000 Professional | 0.4 GB |
|
||||||
|
| `me` | Windows ME | 0.5 GB |
|
||||||
|
| `98` | Windows 98 | 0.7 GB |
|
||||||
|
| `95` | Windows 95 | 0.6 GB |
|
||||||
||||
|
||||
|
||||||
| `2025` | Windows Server 2025 | 7.6 GB |
|
| `2025` | Windows Server 2025 | 7.6 GB |
|
||||||
| `2022` | Windows Server 2022 | 6.0 GB |
|
| `2022` | Windows Server 2022 | 6.0 GB |
|
||||||
|
|||||||
+229
-891
File diff suppressed because it is too large
Load Diff
+3259
File diff suppressed because it is too large
Load Diff
+954
-284
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -13,9 +13,13 @@ cd /run
|
|||||||
. init.sh # Initialize system
|
. init.sh # Initialize system
|
||||||
. memory.sh # Check memory
|
. memory.sh # Check memory
|
||||||
. server.sh # Start webserver
|
. server.sh # Start webserver
|
||||||
|
. download.sh # Load functions
|
||||||
. define.sh # Define versions
|
. define.sh # Define versions
|
||||||
. mido.sh # Download Windows
|
. mido.sh # Download Windows
|
||||||
. answer.sh # Setup answer files
|
. answer.sh # Modern unattended
|
||||||
|
. batch.sh # Win9x unattended
|
||||||
|
. sif.sh # NT5 unattended
|
||||||
|
. legacy.sh # Legacy installs
|
||||||
. image.sh # Detect image files
|
. image.sh # Detect image files
|
||||||
. install.sh # Run installation
|
. install.sh # Run installation
|
||||||
. disk.sh # Initialize disks
|
. disk.sh # Initialize disks
|
||||||
|
|||||||
+308
-431
File diff suppressed because it is too large
Load Diff
+1333
-1067
File diff suppressed because it is too large
Load Diff
+369
@@ -0,0 +1,369 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
setMachine() {
|
||||||
|
|
||||||
|
local id="$1"
|
||||||
|
local iso="$2"
|
||||||
|
local dir="$3"
|
||||||
|
local desc="$4"
|
||||||
|
|
||||||
|
if isLegacy "$id"; then
|
||||||
|
|
||||||
|
if ! legacyInstall "$id" "$iso" "$dir" "$desc"; then
|
||||||
|
error "Failed to prepare $desc ISO!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
writeState "mode" "windows_legacy" || return 1
|
||||||
|
|
||||||
|
case "${id,,}" in
|
||||||
|
|
||||||
|
"win9"* | "winnt4" | "win2k"* | "reactos" )
|
||||||
|
|
||||||
|
writeState "old" "pc" || return 1
|
||||||
|
writeState "type" "auto" || return 1 ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "${id,,}" in
|
||||||
|
|
||||||
|
"winnt4" )
|
||||||
|
writeState "vga" "cirrus" || return 1 ;;
|
||||||
|
|
||||||
|
*) writeState "vga" "std" || return 1 ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "${id,,}" in
|
||||||
|
|
||||||
|
"win9"* | "winnt4" )
|
||||||
|
|
||||||
|
writeState "hv" "N" || return 1
|
||||||
|
writeState "usb" "N" || return 1
|
||||||
|
writeState "port" "on" || return 1
|
||||||
|
writeState "net" "pcnet" || return 1
|
||||||
|
writeState "sound" "AC97" || return 1 ;;
|
||||||
|
|
||||||
|
"win2k"* )
|
||||||
|
|
||||||
|
writeState "hv" "N" || return 1
|
||||||
|
writeState "net" "rtl8139" || return 1
|
||||||
|
writeState "usb" "pci-ohci" || return 1
|
||||||
|
writeState "sound" "usb-audio" || return 1 ;;
|
||||||
|
|
||||||
|
"winxpx"* | "win2003"* )
|
||||||
|
|
||||||
|
writeState "hv" "N" || return 1
|
||||||
|
writeState "type" "blk" || return 1
|
||||||
|
writeState "net" "rtl8139" || return 1
|
||||||
|
writeState "sound" "usb-audio" || return 1 ;;
|
||||||
|
|
||||||
|
"reactos" )
|
||||||
|
|
||||||
|
writeState "sound" "AC97" || return 1
|
||||||
|
writeState "net" "rtl8139" || return 1
|
||||||
|
writeState "usb" "pci-ohci" || return 1
|
||||||
|
|
||||||
|
if isReactOSLiveCD "$iso"; then
|
||||||
|
SYSTEM="$iso"
|
||||||
|
createMarker "kill" || return 1
|
||||||
|
fi ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
restoreMachine || return 1
|
||||||
|
restoreBootMode || return 1
|
||||||
|
|
||||||
|
case "${id,,}" in
|
||||||
|
|
||||||
|
"win95" | "winnt4" )
|
||||||
|
|
||||||
|
# Windows 95 does not support ACPI so disable graceful shutdown
|
||||||
|
createMarker "kill" || return 1 ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "${id,,}" in
|
||||||
|
|
||||||
|
"win9"* | "winnt4" | "win2k"* | *"x86"* )
|
||||||
|
|
||||||
|
# Legacy 32-bit Windows may enter an incompatible PAE/DEP path when the
|
||||||
|
# NX flag is exposed, causing installation failures or repeated resets.
|
||||||
|
#
|
||||||
|
# Long mode is unusable by 32-bit guests and may cause the firmware to
|
||||||
|
# allocate PCI resources above 4 GB, which older systems may not handle.
|
||||||
|
|
||||||
|
writeState "flag" "nx=off,lm=off" || return 1 ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "${id,,}" in
|
||||||
|
|
||||||
|
"win9"* | "winnt4" | "win2k"* | "winxp"* | "win2003"* | \
|
||||||
|
"winvistax86"* | "win7x86"* | "reactos" )
|
||||||
|
|
||||||
|
if isQ35 "$MACHINE"; then
|
||||||
|
|
||||||
|
# pc-q35-2.11 began advertising a synthetic 64-bit PCI MMIO aperture.
|
||||||
|
# Older Windows ACPI implementations may reject that resource layout,
|
||||||
|
# so retain the pre-2.11 behavior for these guests to prevent a
|
||||||
|
# blue screen on XP and others if the 64 bit PCI hole size is >2G.
|
||||||
|
|
||||||
|
writeState "args" "-global q35-pcihost.x-pci-hole64-fix=false" || return 1
|
||||||
|
|
||||||
|
fi ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreMachine() {
|
||||||
|
|
||||||
|
isPlatform "x64" || return 0
|
||||||
|
|
||||||
|
# Restore the saved machine only when q35 is still the default;
|
||||||
|
# an explicit user-selected machine must remain untouched.
|
||||||
|
[[ "${MACHINE,,}" != "q35" ]] && return 0
|
||||||
|
|
||||||
|
MACHINE=""
|
||||||
|
restoreState "MACHINE" "old" || return 1
|
||||||
|
|
||||||
|
# Migrate existing Win9x installs to QEMU 11
|
||||||
|
if [[ "${MACHINE,,}" == "pc-i440fx-2.4" ]]; then
|
||||||
|
MACHINE="pc"
|
||||||
|
writeState "old" "$MACHINE" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$MACHINE" ] && MACHINE="q35"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreMachineState() {
|
||||||
|
|
||||||
|
restoreState "HV" "hv" || return 1
|
||||||
|
restoreState "VGA" "vga" || return 1
|
||||||
|
restoreState "USB" "usb" || return 1
|
||||||
|
restoreState "SOUND" "sound" || return 1
|
||||||
|
restoreState "ADAPTER" "net" || return 1
|
||||||
|
restoreState "VMPORT" "port" || return 1
|
||||||
|
restoreState "CPU_MODEL" "cpu" || return 1
|
||||||
|
restoreState "DISK_TYPE" "type" || return 1
|
||||||
|
|
||||||
|
if [ -z "${BIOS:-}" ] && [ -s "$(stateFile "bios")" ]; then
|
||||||
|
BIOS="$(stateFile "bios")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mergeState "CPU_FLAGS" "flag" "," || return 1
|
||||||
|
mergeState "ARGUMENTS" "args" " " || return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreBootMode() {
|
||||||
|
|
||||||
|
local current="${BOOT_MODE:-}"
|
||||||
|
|
||||||
|
local mode
|
||||||
|
mode=$(readState "mode") || return 1
|
||||||
|
|
||||||
|
[ -n "$mode" ] || return 0
|
||||||
|
|
||||||
|
# A saved legacy mode always wins. A saved modern mode only replaces the
|
||||||
|
# default mode and never an explicit user-selected boot configuration.
|
||||||
|
if [[ "${mode,,}" == "windows_legacy" ]]; then
|
||||||
|
BOOT_MODE="$mode"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${current,,}" in
|
||||||
|
"" | "windows" | "windows_plain" )
|
||||||
|
BOOT_MODE="$mode" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
extractDrivers() {
|
||||||
|
|
||||||
|
local drivers="$1"
|
||||||
|
|
||||||
|
rm -rf "$drivers" || return 1
|
||||||
|
mkdir -p "$drivers" || return 1
|
||||||
|
|
||||||
|
if ! bsdtar -xf /var/drivers.txz -C "$drivers"; then
|
||||||
|
error "Failed to extract drivers!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
legacyInstall() {
|
||||||
|
|
||||||
|
local id="$1"
|
||||||
|
local iso="$2"
|
||||||
|
local dir="$3"
|
||||||
|
local desc="$4"
|
||||||
|
|
||||||
|
case "${id,,}" in
|
||||||
|
"win9"* )
|
||||||
|
Win9xInstall "$id" "$iso" "$dir" "$desc" || return 1 ;;
|
||||||
|
"win2k"* )
|
||||||
|
SIFInstall "$iso" "$dir" "$desc" "2k" || return 1 ;;
|
||||||
|
"winxp"* )
|
||||||
|
SIFInstall "$iso" "$dir" "$desc" "xp" || return 1 ;;
|
||||||
|
"win2003"* )
|
||||||
|
SIFInstall "$iso" "$dir" "$desc" "2k3" || return 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
isReactOSLiveCD() {
|
||||||
|
|
||||||
|
local iso="$1"
|
||||||
|
local files
|
||||||
|
|
||||||
|
files=$(bsdtar -tf "$iso" 2>/dev/null) || return 1
|
||||||
|
|
||||||
|
! grep -Ei '(^|/)reactos/txtsetup\.sif(;1)?$' <<< "$files" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
detectReactOS() {
|
||||||
|
|
||||||
|
local dir="$1"
|
||||||
|
local marker
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 2 -type f \
|
||||||
|
\( -ipath '*/reactos/reactos.inf' -o -ipath '*/reactos/unattend.inf' \) -print -quit) || return 2
|
||||||
|
|
||||||
|
[ -n "$marker" ] || return 1
|
||||||
|
|
||||||
|
DETECTED="reactos"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
detectLegacy() {
|
||||||
|
|
||||||
|
local dir="$1"
|
||||||
|
local marker
|
||||||
|
|
||||||
|
isPlatform "x64" || return 1
|
||||||
|
|
||||||
|
# Legacy media is identified from setup marker files rather than WIM
|
||||||
|
# metadata. The order is intentional because several releases share markers.
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type d -iname 'ia64' -print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
error "Windows IA-64 (Itanium) images are not supported by this container!"
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type d -iname WIN95 -print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="win95"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type d -iname WIN98 -print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="win98"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type d -iname WIN9X -print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="win9x"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type f \
|
||||||
|
\( \
|
||||||
|
-iname CDROM_W.40 -o \
|
||||||
|
-iname CDROM_S.40 -o \
|
||||||
|
-iname CDROM_TS.40 \
|
||||||
|
\) \
|
||||||
|
-print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="winnt4"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type f -iname CDROM_NT.5 -print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type f \
|
||||||
|
\( \
|
||||||
|
-iname CDROM_IA.5 -o \
|
||||||
|
-iname CDROM_ID.5 -o \
|
||||||
|
-iname CDROM_IP.5 -o \
|
||||||
|
-iname CDROM_IS.5 \
|
||||||
|
\) \
|
||||||
|
-print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="win2k"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# WIN51 identifies the NT 5.1/5.2 media family; the companion marker then
|
||||||
|
# distinguishes XP x86, XP x64, and Server 2003.
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -iname WIN51 -print -quit) || return 2
|
||||||
|
[ -n "$marker" ] || return 1
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type f -iname WIN51AP -print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="winxpx64"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type f \
|
||||||
|
\( \
|
||||||
|
-iname WIN51IC -o \
|
||||||
|
-iname WIN51IP -o \
|
||||||
|
-iname setupxp.htm \
|
||||||
|
\) \
|
||||||
|
-print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="winxpx86"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
marker=$(find "$dir" -maxdepth 1 -type f \
|
||||||
|
\( \
|
||||||
|
-iname WIN51IS -o \
|
||||||
|
-iname WIN51IA -o \
|
||||||
|
-iname WIN51IB -o \
|
||||||
|
-iname WIN51ID -o \
|
||||||
|
-iname WIN51IL -o \
|
||||||
|
-iname WIN51AA -o \
|
||||||
|
-iname WIN51AD -o \
|
||||||
|
-iname WIN51AS -o \
|
||||||
|
-iname WIN51MA -o \
|
||||||
|
-iname WIN51MD -o \
|
||||||
|
-iname WIN51MP \
|
||||||
|
\) \
|
||||||
|
-print -quit) || return 2
|
||||||
|
|
||||||
|
if [ -n "$marker" ]; then
|
||||||
|
DETECTED="win2003r2"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
+42
-29
@@ -7,8 +7,6 @@ handleCurlError() {
|
|||||||
local server="$2"
|
local server="$2"
|
||||||
local reason="${3:-}"
|
local reason="${3:-}"
|
||||||
|
|
||||||
local signal
|
|
||||||
|
|
||||||
if [ -n "$reason" ] && (( code <= 125 )); then
|
if [ -n "$reason" ] && (( code <= 125 )); then
|
||||||
error "Request to $server servers failed: ${reason%.}."
|
error "Request to $server servers failed: ${reason%.}."
|
||||||
return 1
|
return 1
|
||||||
@@ -23,6 +21,7 @@ handleCurlError() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local signal
|
||||||
signal=$(kill -l "$((code - 128))" 2>/dev/null || true)
|
signal=$(kill -l "$((code - 128))" 2>/dev/null || true)
|
||||||
|
|
||||||
case "$signal" in
|
case "$signal" in
|
||||||
@@ -72,10 +71,7 @@ curlRequest() {
|
|||||||
rm -f "$log"
|
rm -f "$log"
|
||||||
handleCurlError "$rc" "$server" "$reason" || :
|
handleCurlError "$rc" "$server" "$reason" || :
|
||||||
|
|
||||||
if (( rc >= 129 )); then
|
(( rc >= 129 )) && return "$rc"
|
||||||
return "$rc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -179,13 +175,16 @@ downloadWindowsLink() {
|
|||||||
--max-filesize 100K \
|
--max-filesize 100K \
|
||||||
-- "$skuUrl") || return
|
-- "$skuUrl") || return
|
||||||
|
|
||||||
# Let jq parsing failures propagate so malformed API data is not mistaken
|
skuId=$(printf '%s\n' "$skuJson" | jq --arg LANG "$language" -r 'first(.Skus[]? | select(.Language == $LANG) | .Id) // empty') 2>/dev/null || skuId=""
|
||||||
# for a normal missing-result response. The same applies to the link data.
|
|
||||||
skuId=$(printf '%s\n' "$skuJson" | jq --arg LANG "$language" -r 'first(.Skus[]? | select(.Language == $LANG) | .Id) // empty') 2>/dev/null || return
|
|
||||||
|
|
||||||
if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]]; then
|
if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]]; then
|
||||||
language=$(getLanguage "$lang" "desc")
|
if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then
|
||||||
error "No download in the $language language available for $desc!"
|
language=$(getLanguage "$lang" "desc")
|
||||||
|
error "No download in the $language language available for $desc!"
|
||||||
|
else
|
||||||
|
error "Microsoft server provided us no SKU ID in response to our request!"
|
||||||
|
info "Response: $skuJson"
|
||||||
|
fi
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -218,10 +217,10 @@ downloadWindowsLink() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
link=$(printf '%s\n' "$linkJson" | jq --argjson TYPE "$type" -r 'first(.ProductDownloadOptions[]? | select(.DownloadType == $TYPE) | .Uri) // empty') 2>/dev/null || return
|
link=$(printf '%s\n' "$linkJson" | jq --argjson TYPE "$type" -r 'first(.ProductDownloadOptions[]? | select(.DownloadType == $TYPE) | .Uri) // empty') 2>/dev/null || link=""
|
||||||
|
|
||||||
if [ -z "$link" ] || [[ "${link,,}" == "null" ]]; then
|
if [ -z "$link" ] || [[ "${link,,}" == "null" ]]; then
|
||||||
error "Microsoft server gave us no download link to our request for an automated download!"
|
error "Microsoft server provided us no download link to our request for an automated download!"
|
||||||
info "Response: $linkJson"
|
info "Response: $linkJson"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -291,7 +290,7 @@ downloadWindows() {
|
|||||||
grep -Eio "<option[^>]*value=[\"'][0-9]+[\"'][^>]*>[[:space:]]*Windows[^<]*" |
|
grep -Eio "<option[^>]*value=[\"'][0-9]+[\"'][^>]*>[[:space:]]*Windows[^<]*" |
|
||||||
sed -nE "s/.*value=[\"']([0-9]+)[\"'].*/\1/p" |
|
sed -nE "s/.*value=[\"']([0-9]+)[\"'].*/\1/p" |
|
||||||
sed -n '1p' |
|
sed -n '1p' |
|
||||||
cut -c 1-16) || return
|
cut -c 1-16) || productId=""
|
||||||
enabled "$DEBUG" && echo "$productId"
|
enabled "$DEBUG" && echo "$productId"
|
||||||
|
|
||||||
if [ -z "$productId" ]; then
|
if [ -z "$productId" ]; then
|
||||||
@@ -321,7 +320,7 @@ downloadWindowsEval() {
|
|||||||
type="iot"
|
type="iot"
|
||||||
winVer="windows-11-iot-enterprise-ltsc-eval" ;;
|
winVer="windows-11-iot-enterprise-ltsc-eval" ;;
|
||||||
"win11${PLATFORM,,}-enterprise-ltsc-eval" )
|
"win11${PLATFORM,,}-enterprise-ltsc-eval" )
|
||||||
if [[ "${PLATFORM,,}" == "arm64" ]]; then
|
if isPlatform "arm64"; then
|
||||||
type="iot"
|
type="iot"
|
||||||
winVer="windows-11-iot-enterprise-ltsc-eval"
|
winVer="windows-11-iot-enterprise-ltsc-eval"
|
||||||
else
|
else
|
||||||
@@ -579,11 +578,13 @@ getWindows() {
|
|||||||
"win81${PLATFORM,,}"* | \
|
"win81${PLATFORM,,}"* | \
|
||||||
"win10${PLATFORM,,}-enterprise-ltsc-eval" | \
|
"win10${PLATFORM,,}-enterprise-ltsc-eval" | \
|
||||||
"win11${PLATFORM,,}-enterprise-iot-eval" )
|
"win11${PLATFORM,,}-enterprise-iot-eval" )
|
||||||
|
|
||||||
if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then
|
if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then
|
||||||
error "No download in the $language language available for $edition!"
|
error "No download in the $language language available for $edition!"
|
||||||
MIDO_URL=""
|
MIDO_URL=""
|
||||||
return 1
|
return 1
|
||||||
fi ;;
|
fi ;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# ARM64 downloads exist only for the explicitly supported Windows 11
|
# ARM64 downloads exist only for the explicitly supported Windows 11
|
||||||
@@ -593,24 +594,28 @@ getWindows() {
|
|||||||
"win11${PLATFORM,,}" ) ;;
|
"win11${PLATFORM,,}" ) ;;
|
||||||
"win11${PLATFORM,,}-enterprise"* ) ;;
|
"win11${PLATFORM,,}-enterprise"* ) ;;
|
||||||
* )
|
* )
|
||||||
if [[ "${PLATFORM,,}" != "x64" ]]; then
|
|
||||||
|
if ! isPlatform "x64"; then
|
||||||
error "No download for the ${PLATFORM^^} platform available for $edition!"
|
error "No download for the ${PLATFORM^^} platform available for $edition!"
|
||||||
MIDO_URL=""
|
MIDO_URL=""
|
||||||
return 1
|
return 1
|
||||||
fi ;;
|
fi ;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Prefer live Microsoft download routes. Unsupported or failed live routes
|
# Prefer live Microsoft download routes. Unsupported or failed live routes
|
||||||
# fall through to the configured static catalog below.
|
# fall through to the configured static catalog below.
|
||||||
case "${version,,}" in
|
case "${version,,}" in
|
||||||
|
|
||||||
"win10x64" | "win11${PLATFORM,,}" )
|
"win10x64" | "win11${PLATFORM,,}" )
|
||||||
|
|
||||||
if downloadWindows "$version" "$lang" "$edition"; then
|
if downloadWindows "$version" "$lang" "$edition"; then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
rc=$?
|
rc=$?
|
||||||
(( rc == 1 )) || return "$rc"
|
fi
|
||||||
fi ;;
|
|
||||||
|
(( rc == 1 )) || return "$rc" ;;
|
||||||
|
|
||||||
"win11${PLATFORM,,}-enterprise"* )
|
"win11${PLATFORM,,}-enterprise"* )
|
||||||
|
|
||||||
@@ -618,8 +623,9 @@ getWindows() {
|
|||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
rc=$?
|
rc=$?
|
||||||
(( rc == 1 )) || return "$rc"
|
fi
|
||||||
fi ;;
|
|
||||||
|
(( rc == 1 )) || return "$rc" ;;
|
||||||
|
|
||||||
"win2025-eval" | "win2022-eval" | "win2019-eval" | \
|
"win2025-eval" | "win2022-eval" | "win2019-eval" | \
|
||||||
"win2019-hv" | "win2016-eval" | "win2012r2-eval" )
|
"win2019-hv" | "win2016-eval" | "win2012r2-eval" )
|
||||||
@@ -628,14 +634,16 @@ getWindows() {
|
|||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
rc=$?
|
rc=$?
|
||||||
(( rc == 1 )) || return "$rc"
|
fi
|
||||||
fi ;;
|
|
||||||
|
(( rc == 1 )) || return "$rc" ;;
|
||||||
|
|
||||||
"win2008r2"*| "win81${PLATFORM,,}"* | "win10${PLATFORM,,}-enterprise"* ) ;;
|
"win2008r2"*| "win81${PLATFORM,,}"* | "win10${PLATFORM,,}-enterprise"* ) ;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
error "Invalid VERSION specified, value \"$version\" is not recognized!"
|
error "Invalid VERSION specified, value \"$version\" is not recognized!"
|
||||||
return 1 ;;
|
return 1 ;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Static catalog URLs are the last resort after live Microsoft methods are
|
# Static catalog URLs are the last resort after live Microsoft methods are
|
||||||
@@ -995,10 +1003,7 @@ getESD() {
|
|||||||
|
|
||||||
rm -f "$log"
|
rm -f "$log"
|
||||||
|
|
||||||
if (( rc >= 129 )); then
|
(( rc >= 129 )) && return "$rc"
|
||||||
return "$rc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1117,7 +1122,7 @@ verifyFile() {
|
|||||||
info "Successfully verified $type!" && return 0
|
info "Successfully verified $type!" && return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
error "The downloaded file has an unknown $algo checksum: $hash , as the expected value was: $check. Please report this at $SUPPORT/issues"
|
warn "the downloaded file has an unknown $algo checksum: $hash , as the expected value was: $check. Please report this at $SUPPORT/issues"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1209,6 +1214,7 @@ tryDownload() {
|
|||||||
if ! rm -f -- "$iso" "$iso.aria2"; then
|
if ! rm -f -- "$iso" "$iso.aria2"; then
|
||||||
warn "failed to remove invalid download \"$iso\"!"
|
warn "failed to remove invalid download \"$iso\"!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1271,13 +1277,18 @@ downloadImage() {
|
|||||||
local tried="n" success="n" seconds="5"
|
local tried="n" success="n" seconds="5"
|
||||||
local i url sum size base language desc web_desc rc
|
local i url sum size base language desc web_desc rc
|
||||||
|
|
||||||
if [[ "${version,,}" == "http"* ]]; then
|
if isURL "$version"; then
|
||||||
|
|
||||||
base=$(basename "$iso")
|
base=$(basename "$iso")
|
||||||
desc=$(fromFile "$base")
|
desc=$(fromFile "$base")
|
||||||
web_desc="$desc"
|
web_desc="$desc"
|
||||||
|
|
||||||
tryDownload "$iso" "$version" "" "" "$desc" "$seconds" "$web_desc" || return
|
tryDownload "$iso" "$version" "" "" "$desc" "$seconds" "$web_desc" || {
|
||||||
|
rc=$?
|
||||||
|
error "Failed to download the Windows image from the specified URL!"
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1446,6 +1457,8 @@ downloadImage() {
|
|||||||
|
|
||||||
if [[ "$tried" == "n" ]]; then
|
if [[ "$tried" == "n" ]]; then
|
||||||
error "No download method is available for $desc!"
|
error "No download method is available for $desc!"
|
||||||
|
else
|
||||||
|
error "All download methods failed for $desc!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
+43
-66
@@ -11,7 +11,7 @@ SHUTDOWN_SIGNAL=0
|
|||||||
|
|
||||||
QEMU_PTY="$QEMU_DIR/qemu.pty"
|
QEMU_PTY="$QEMU_DIR/qemu.pty"
|
||||||
QEMU_END="$QEMU_DIR/qemu.end"
|
QEMU_END="$QEMU_DIR/qemu.end"
|
||||||
ACPI_SOCKET="$QEMU_DIR/acpi.sock"
|
ACPI_SOCKET="$QEMU_DIR/monitor.sock"
|
||||||
CONSOLE_PID="$QEMU_DIR/console.pid"
|
CONSOLE_PID="$QEMU_DIR/console.pid"
|
||||||
CONSOLE_SOCKET="$QEMU_DIR/console.sock"
|
CONSOLE_SOCKET="$QEMU_DIR/console.sock"
|
||||||
QEMU_START_PID="$QEMU_DIR/qemu.start.pid"
|
QEMU_START_PID="$QEMU_DIR/qemu.start.pid"
|
||||||
@@ -28,7 +28,7 @@ bootStatus() {
|
|||||||
|
|
||||||
[ ! -s "$QEMU_PTY" ] && return 1
|
[ ! -s "$QEMU_PTY" ] && return 1
|
||||||
|
|
||||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
if isLegacyBoot; then
|
||||||
local line last recent
|
local line last recent
|
||||||
|
|
||||||
# Only inspect output produced after the most recent BIOS boot attempt so
|
# Only inspect output produced after the most recent BIOS boot attempt so
|
||||||
@@ -44,6 +44,9 @@ bootStatus() {
|
|||||||
if grep -Fq \
|
if grep -Fq \
|
||||||
-e "No bootable device." \
|
-e "No bootable device." \
|
||||||
-e "BOOTMGR is missing" \
|
-e "BOOTMGR is missing" \
|
||||||
|
-e "Replace the disk, and then press any key" \
|
||||||
|
-e "The following file is missing or corrupted:" \
|
||||||
|
-e "Type the name of the Windows loader" \
|
||||||
<<< "$recent"; then
|
<<< "$recent"; then
|
||||||
return 2
|
return 2
|
||||||
fi
|
fi
|
||||||
@@ -130,7 +133,7 @@ waitForBoot() {
|
|||||||
elif bootKeyReady; then
|
elif bootKeyReady; then
|
||||||
(( keyWait += 1 ))
|
(( keyWait += 1 ))
|
||||||
|
|
||||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
if isLegacyBoot; then
|
||||||
# Keep the legacy fallback at about one second after the DVD marker.
|
# Keep the legacy fallback at about one second after the DVD marker.
|
||||||
if (( keyWait >= 5 )); then
|
if (( keyWait >= 5 )); then
|
||||||
if sendKey ret 0 100 6 0.25; then
|
if sendKey ret 0 100 6 0.25; then
|
||||||
@@ -251,20 +254,24 @@ legacyBootReady() {
|
|||||||
grep -Fq "Loading FreeLoader..." <<< "$recent" && return 0
|
grep -Fq "Loading FreeLoader..." <<< "$recent" && return 0
|
||||||
grep -Fq "No bootable device." <<< "$recent" && return 1
|
grep -Fq "No bootable device." <<< "$recent" && return 1
|
||||||
grep -Fq "BOOTMGR is missing" <<< "$recent" && return 1
|
grep -Fq "BOOTMGR is missing" <<< "$recent" && return 1
|
||||||
|
grep -Fq "Replace the disk, and then press any key" <<< "$recent" && return 1
|
||||||
grep -Fq "Boot failed: not a bootable disk" <<< "$recent" && return 1
|
grep -Fq "Boot failed: not a bootable disk" <<< "$recent" && return 1
|
||||||
grep -Fq "Boot failed: could not read the boot disk" <<< "$recent" && return 1
|
grep -Fq "Boot failed: could not read the boot disk" <<< "$recent" && return 1
|
||||||
|
grep -Fq "The following file is missing or corrupted:" <<< "$recent" && return 1
|
||||||
|
grep -Fq "Type the name of the Windows loader" <<< "$recent" && return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ready() {
|
ready() {
|
||||||
|
|
||||||
# The marker means installation completed previously, so shutdown no longer
|
# The marker means installation completed previously, so shutdown
|
||||||
# needs to infer guest readiness from firmware output.
|
# no longer needs to infer guest readiness from firmware output.
|
||||||
[ -f "$STORAGE/windows.boot" ] && return 0
|
hasBootMarker && return 0
|
||||||
|
|
||||||
[ ! -s "$QEMU_PTY" ] && return 1
|
[ ! -s "$QEMU_PTY" ] && return 1
|
||||||
|
|
||||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
if isLegacyBoot; then
|
||||||
legacyBootReady && return 0
|
legacyBootReady && return 0
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -343,32 +350,26 @@ sendKey() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
supportsBootKey() {
|
|
||||||
|
|
||||||
local id="$1"
|
|
||||||
|
|
||||||
[[ "${id,,}" == "win"* ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
needsBootKey() {
|
needsBootKey() {
|
||||||
|
|
||||||
[ ! -s "$BOOT" ] && return 1
|
hasImage "$BOOT" || return 1
|
||||||
[[ "${BOOT,,}" != *".iso" ]] && return 1
|
|
||||||
[ -f "$STORAGE/windows.boot" ] && return 1
|
|
||||||
|
|
||||||
supportsBootKey "$DETECTED"
|
hasCompletedInstall && return 1
|
||||||
|
supportsBootKey "$DETECTED" || return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
bootKeyReady() {
|
bootKeyReady() {
|
||||||
|
|
||||||
[ ! -s "$QEMU_PTY" ] && return 1
|
[ ! -s "$QEMU_PTY" ] && return 1
|
||||||
|
|
||||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
if isLegacyBoot; then
|
||||||
grep -Fq "Booting from DVD/CD" "$QEMU_PTY"
|
grep -Fq "Booting from DVD/CD" "$QEMU_PTY"
|
||||||
return $?
|
return $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${PLATFORM,,}" == "arm64" ]]; then
|
if isPlatform "arm64"; then
|
||||||
grep -Eq "$UEFI_USB_BOOT_PATTERN" "$QEMU_PTY"
|
grep -Eq "$UEFI_USB_BOOT_PATTERN" "$QEMU_PTY"
|
||||||
else
|
else
|
||||||
grep -Eq "$UEFI_DVD_BOOT_PATTERN" "$QEMU_PTY"
|
grep -Eq "$UEFI_DVD_BOOT_PATTERN" "$QEMU_PTY"
|
||||||
@@ -377,7 +378,7 @@ bootKeyReady() {
|
|||||||
|
|
||||||
getBootMarker() {
|
getBootMarker() {
|
||||||
|
|
||||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
if isLegacyBoot; then
|
||||||
grep -nE "$LEGACY_BOOT_PATTERN" "$QEMU_PTY" | tail -1
|
grep -nE "$LEGACY_BOOT_PATTERN" "$QEMU_PTY" | tail -1
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -389,9 +390,7 @@ getBootMarker() {
|
|||||||
|
|
||||||
markWindowsBooted() {
|
markWindowsBooted() {
|
||||||
|
|
||||||
local file="$STORAGE/windows.boot"
|
if hasBootMarker || [ ! -f "$BOOT" ]; then
|
||||||
|
|
||||||
if [ -f "$file" ] || [ ! -f "$BOOT" ]; then
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -399,19 +398,13 @@ markWindowsBooted() {
|
|||||||
# now booting from the installed disk rather than from setup media.
|
# now booting from the installed disk rather than from setup media.
|
||||||
ready || return 0
|
ready || return 0
|
||||||
|
|
||||||
if ! touch "$file"; then
|
createMarker "boot" || return 0
|
||||||
warn "failed to create Windows installation marker!"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! setOwner "$file"; then
|
|
||||||
rm -f "$file"
|
|
||||||
warn "failed to set the owner for \"$file\" !"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! disabled "$REMOVE"; then
|
if ! disabled "$REMOVE"; then
|
||||||
removeImage "$BOOT" || :
|
case "${BOOT,,}" in
|
||||||
|
*.img | *.raw | *.qcow2 ) ;;
|
||||||
|
* ) removeImage "$BOOT" || : ;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "$STORAGE/setup.img" 2>/dev/null || :
|
rm -f "$STORAGE/setup.img" 2>/dev/null || :
|
||||||
@@ -423,29 +416,26 @@ finish() {
|
|||||||
|
|
||||||
local reason=$1 failed=0
|
local reason=$1 failed=0
|
||||||
|
|
||||||
# QEMU_END distinguishes an expected shutdown path from an unexpected QEMU
|
# A nonzero exit is unexpected only when QEMU_END is missing.
|
||||||
# exit carrying the same process status.
|
|
||||||
if [ ! -f "$QEMU_END" ] && (( reason != 0 )); then
|
if [ ! -f "$QEMU_END" ] && (( reason != 0 )); then
|
||||||
failed=1
|
failed=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
touch "$QEMU_END"
|
touch "$QEMU_END" || :
|
||||||
|
|
||||||
forceKillQemu "$reason"
|
forceKillQemu "$reason"
|
||||||
|
|
||||||
if [ ! -f "$STORAGE/windows.boot" ]; then
|
if ! hasBootMarker; then
|
||||||
markWindowsBooted
|
markWindowsBooted
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cleanupHelpers \
|
cleanupHelpers "${SMB_PID:-}" "${NMB_PID:-}" "${DDN_PID:-}"
|
||||||
"${SMB_PID:-}" \
|
|
||||||
"${NMB_PID:-}" \
|
|
||||||
"${DDN_PID:-}"
|
|
||||||
|
|
||||||
if ! waitQemuExit 10; then
|
if ! waitQemuExit 10; then
|
||||||
warn "Timed out while waiting for $(app) to exit!"
|
warn "Timed out while waiting for $(app) to exit!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
stopConsole
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if (( failed == 0 )); then
|
if (( failed == 0 )); then
|
||||||
@@ -457,27 +447,6 @@ finish() {
|
|||||||
exit "$reason"
|
exit "$reason"
|
||||||
}
|
}
|
||||||
|
|
||||||
abortDuringSetup() {
|
|
||||||
|
|
||||||
local code="$1"
|
|
||||||
|
|
||||||
# Before Windows boots from disk, ACPI may be ignored or interpreted by setup
|
|
||||||
# itself. Terminate QEMU directly instead of waiting for a graceful shutdown.
|
|
||||||
if [[ "${DETECTED,,}" != "reactos" ]] || [ -n "${CUSTOM:-}" ]; then
|
|
||||||
info "Cannot send ACPI signal during $(app) setup, terminating..."
|
|
||||||
else
|
|
||||||
info "ReactOS LiveCD does not support ACPI shutdown, terminating..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
terminateQemu
|
|
||||||
|
|
||||||
if ! waitQemuExit 10; then
|
|
||||||
warn "Timed out while waiting for $(app) to exit!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
finish "$code"
|
|
||||||
}
|
|
||||||
|
|
||||||
gracefulShutdown() {
|
gracefulShutdown() {
|
||||||
|
|
||||||
local sig="$1"
|
local sig="$1"
|
||||||
@@ -526,8 +495,16 @@ gracefulShutdown() {
|
|||||||
finish "$code"
|
finish "$code"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! ready; then
|
if hasMarker "kill"; then
|
||||||
abortDuringSetup "$code"
|
|
||||||
|
info "This $(app) version does not support ACPI shutdown, decreasing timeout to 1 second..."
|
||||||
|
TIMEOUT=7
|
||||||
|
|
||||||
|
elif ! ready || { hasSystemImage && ! hasBootMarker; }; then
|
||||||
|
|
||||||
|
info "$(app) will ignore ACPI signals during setup, decreasing timeout to 10 seconds..."
|
||||||
|
TIMEOUT=13
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
normalizeTimeout 105
|
normalizeTimeout 105
|
||||||
|
|||||||
+1
-1
@@ -388,7 +388,7 @@ isUserMode && return 0
|
|||||||
|
|
||||||
# Older Windows versions discover shares through NetBIOS, while modern Windows
|
# Older Windows versions discover shares through NetBIOS, while modern Windows
|
||||||
# uses Web Services Discovery.
|
# uses Web Services Discovery.
|
||||||
if [[ "${BOOT_MODE:-}" == "windows_legacy" ]]; then
|
if isLegacyBoot; then
|
||||||
startNetbios || :
|
startNetbios || :
|
||||||
else
|
else
|
||||||
startWsddn || :
|
startWsddn || :
|
||||||
|
|||||||
+1251
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user