diff --git a/src/entry.sh b/src/entry.sh index c1cf0d6..412ee75 100644 --- a/src/entry.sh +++ b/src/entry.sh @@ -27,6 +27,7 @@ info "Booting $APP using $VERS..." terminal tail -fn +0 "$QEMU_LOG" 2>/dev/null & -cat "$QEMU_TERM" 2>/dev/null & wait $! || : +cat "$QEMU_TERM" 2> /dev/null | tee "$QEMU_PTY" & +wait $! || : sleep 1 && finish 0 diff --git a/src/install.sh b/src/install.sh index 18fe266..de16a69 100644 --- a/src/install.sh +++ b/src/install.sh @@ -4,6 +4,10 @@ set -Eeuo pipefail : "${MANUAL:=""}" : "${VERSION:="win11x64"}" +if [[ "${VERSION}" == \"*\" || "${VERSION}" == \'*\' ]]; then + VERSION="${VERSION:1:-1}" +fi + [[ "${VERSION,,}" == "11" ]] && VERSION="win11x64" [[ "${VERSION,,}" == "win11" ]] && VERSION="win11x64" @@ -41,332 +45,405 @@ CUSTOM="custom.iso" [ ! -f "$STORAGE/$CUSTOM" ] && CUSTOM="custom.IMG" [ ! -f "$STORAGE/$CUSTOM" ] && CUSTOM="CUSTOM.IMG" -MSG="Windows is being started, please wait..." - -if [ -f "$STORAGE/$CUSTOM" ]; then - - EXTERNAL="Y" - BASE="$CUSTOM" - -else - - CUSTOM="" - - if [[ "${VERSION,,}" == "http"* ]]; then - EXTERNAL="Y" - else - EXTERNAL="N" - fi - - if [[ "$EXTERNAL" != [Yy1]* ]]; then - - BASE="$VERSION.iso" - - if [ ! -f "$STORAGE/$BASE" ]; then - MSG="Windows is being downloaded, please wait..." - fi - - else - - BASE=$(basename "${VERSION%%\?*}") - : "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}" - BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g') - - if [ ! -f "$STORAGE/$BASE" ]; then - MSG="Image '$BASE' is being downloaded, please wait..." - fi - - fi - - [[ "${BASE,,}" == "custom."* ]] && BASE="windows.iso" - -fi - -html "$MSG" - TMP="$STORAGE/tmp" -[ -z "$MANUAL" ] && MANUAL="N" - -if [ -f "$STORAGE/$BASE" ]; then - - # Check if the ISO was already processed by our script - MAGIC=$(dd if="$STORAGE/$BASE" seek=0 bs=1 count=1 status=none | tr -d '\000') - MAGIC="$(printf '%s' "$MAGIC" | od -A n -t x1 -v | tr -d ' \n')" - - if [[ "$MAGIC" == "16" ]]; then - - if [[ "$MANUAL" = [Yy1]* ]]; then - rm -rf "$TMP" - return 0 - fi - - FOUND="N" - if [ -f "$STORAGE/data.img" ] || [ -f "$STORAGE/data.qcow2" ]; then - FOUND="Y" - else - [ -b "${DEVICE:-}" ] && FOUND="Y" - fi - - if [[ "$FOUND" == "Y" ]]; then - rm -rf "$TMP" - return 0 - fi - - fi - - EXTERNAL="Y" - CUSTOM="$BASE" - -fi - -mkdir -p "$TMP" - -if [ ! -f "$STORAGE/$CUSTOM" ]; then - CUSTOM="" - ISO="$TMP/$BASE" -else - ISO="$STORAGE/$CUSTOM" -fi - -rm -f "$TMP/$BASE" - -if [ ! -f "$ISO" ]; then - - if [[ "$EXTERNAL" != [Yy1]* ]]; then - - cd "$TMP" - /run/mido.sh "$VERSION" - cd /run - - else - - info "Downloading $BASE as boot image..." - - # Check if running with interactive TTY or redirected to docker log - if [ -t 1 ]; then - PROGRESS="--progress=bar:noscroll" - else - PROGRESS="--progress=dot:giga" - fi - - { wget "$VERSION" -O "$ISO" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || : - - (( rc != 0 )) && error "Failed to download $VERSION, reason: $rc" && exit 60 - - fi - - [ ! -f "$ISO" ] && error "Failed to download $VERSION" && exit 61 - -fi - -SIZE=$(stat -c%s "$ISO") -SIZE_GB=$(( (SIZE + 1073741823)/1073741824 )) - -if ((SIZE<10000000)); then - error "Invalid ISO file: Size is smaller than 10 MB" && exit 62 -fi - -SPACE=$(df --output=avail -B 1 "$TMP" | tail -n 1) -SPACE_GB=$(( (SPACE + 1073741823)/1073741824 )) - -if (( SIZE > SPACE )); then - error "Not enough free space in $STORAGE, have $SPACE_GB GB available but need at least $SIZE_GB GB." && exit 63 -fi - -if [ -n "$CUSTOM" ]; then - MSG="Extracting local ISO image..." -else - MSG="Extracting downloaded ISO image..." -fi - -info "$MSG" && html "$MSG" - DIR="$TMP/unpack" -rm -rf "$DIR" - -7z x "$ISO" -o"$DIR" > /dev/null - FB="falling back to manual installation!" ETFS="boot/etfsboot.com" EFISYS="efi/microsoft/boot/efisys_noprompt.bin" -if [ ! -f "$DIR/$ETFS" ] || [ ! -f "$DIR/$EFISYS" ]; then +replaceXML() { - if [ ! -f "$DIR/$ETFS" ]; then - warn "failed to locate file 'etfsboot.com' in ISO image, $FB" - else - warn "failed to locate file 'efisys_noprompt.bin' in ISO image, $FB" + local dir="$1" + local asset="$2" + + local path="$dir/autounattend.xml" + [ -f "$path" ] && mv -f "$asset" "$path" + path="$dir/Autounattend.xml" + [ -f "$path" ] && mv -f "$asset" "$path" + path="$dir/AutoUnattend.xml" + [ -f "$path" ] && mv -f "$asset" "$path" + path="$dir/autounattend.XML" + [ -f "$path" ] && mv -f "$asset" "$path" + path="$dir/Autounattend.XML" + [ -f "$path" ] && mv -f "$asset" "$path" + path="$dir/AutoUnattend.XML" + [ -f "$path" ] && mv -f "$asset" "$path" + path="$dir/AUTOUNATTEND.xml" + [ -f "$path" ] && mv -f "$asset" "$path" + path="$dir/AUTOUNATTEND.XML" + [ -f "$path" ] && mv -f "$asset" "$path" + + return 0 +} + +hasDisk() { + + [ -b "${DEVICE:-}" ] && return 0 + + if [ -f "$STORAGE/data.img" ] || [ -f "$STORAGE/data.qcow2" ]; then + return 0 fi - # Mark ISO as prepared via magic byte - printf '\x16' | dd of="$ISO" bs=1 seek=0 count=1 conv=notrunc status=none + return 1 +} - [[ "$ISO" != "$STORAGE/$BASE" ]] && mv -f "$ISO" "$STORAGE/$BASE" +skipInstall() { + + if hasDisk && [ -f "$STORAGE/windows.boot" ]; then + return 0 + fi + + return 1 +} + +finishInstall() { + + local iso="$1" + + # Mark ISO as prepared via magic byte + printf '\x16' | dd of="$iso" bs=1 seek=0 count=1 conv=notrunc status=none rm -f "$STORAGE/windows.ver" + rm -f "$STORAGE/windows.boot" cp /run/version "$STORAGE/windows.ver" rm -rf "$TMP" return 0 -fi +} -[ -z "$CUSTOM" ] && rm -f "$ISO" +startInstall() { -XML="" + local msg="Windows is being started, please wait..." -if [[ "$MANUAL" != [Yy1]* ]]; then + if [ -f "$STORAGE/$CUSTOM" ]; then - if [[ "$EXTERNAL" != [Yy1]* ]]; then - [ -z "$CUSTOM" ] && XML="$VERSION.xml" - fi - - if [ ! -f "/run/assets/$XML" ]; then - - MSG="Detecting Windows version from ISO image..." - info "$MSG" && html "$MSG" - - LOC="$DIR/sources/install.wim" - [ ! -f "$LOC" ] && LOC="$DIR/sources/install.esd" - - if [ -f "$LOC" ]; then - - DETECTED="" - TAG="DISPLAYNAME" - RESULT=$(wimlib-imagex info -xml "$LOC" | tr -d '\000') - NAME=$(sed -n "/$TAG/{s/.*<$TAG>\(.*\)<\/$TAG>.*/\1/;p}" <<< "$RESULT") - - [[ "${NAME,,}" == *"windows 11"* ]] && DETECTED="win11x64" - [[ "${NAME,,}" == *"windows 10"* ]] && DETECTED="win10x64" - [[ "${NAME,,}" == *"windows 8"* ]] && DETECTED="win81x64" - [[ "${NAME,,}" == *"server 2022"* ]] && DETECTED="win2022-eval" - [[ "${NAME,,}" == *"server 2019"* ]] && DETECTED="win2019-eval" - [[ "${NAME,,}" == *"server 2016"* ]] && DETECTED="win2016-eval" - - if [ -z "$DETECTED" ]; then - - TAG="PRODUCTNAME" - NAME2=$(sed -n "/$TAG/{s/.*<$TAG>\(.*\)<\/$TAG>.*/\1/;p}" <<< "$RESULT") - [ -z "$NAME" ] && NAME="$NAME2" - - [[ "${NAME2,,}" == *"windows 11"* ]] && DETECTED="win11x64" - [[ "${NAME2,,}" == *"windows 10"* ]] && DETECTED="win10x64" - [[ "${NAME2,,}" == *"windows 8"* ]] && DETECTED="win81x64" - [[ "${NAME2,,}" == *"server 2022"* ]] && DETECTED="win2022-eval" - [[ "${NAME2,,}" == *"server 2019"* ]] && DETECTED="win2019-eval" - [[ "${NAME2,,}" == *"server 2016"* ]] && DETECTED="win2016-eval" - - fi - - if [ -n "$DETECTED" ]; then - - XML="$DETECTED.xml" - - if [ -f "/run/assets/$XML" ]; then - echo "Detected image of type '$DETECTED', which supports automatic installation." - else - XML="" - warn "detected image of type '$DETECTED', but no matching XML file exists, $FB." - fi - - else - if [ -z "$NAME" ]; then - warn "failed to detect Windows version from image, $FB" - else - if [[ "${NAME,,}" == "windows 7" ]]; then - warn "detected Windows 7 image, $FB" - else - warn "failed to detect Windows version from string '$NAME', $FB" - fi - fi - fi - else - warn "failed to locate 'install.wim' or 'install.esd' in ISO image, $FB" - fi - fi -fi - -ASSET="/run/assets/$XML" - -if [ -f "$ASSET" ]; then - - LOC="$DIR/autounattend.xml" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - LOC="$DIR/Autounattend.xml" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - LOC="$DIR/AutoUnattend.xml" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - LOC="$DIR/autounattend.XML" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - LOC="$DIR/Autounattend.XML" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - LOC="$DIR/AutoUnattend.XML" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - LOC="$DIR/AUTOUNATTEND.xml" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - LOC="$DIR/AUTOUNATTEND.XML" - [ -f "$LOC" ] && mv -f "$ASSET" "$LOC" - - LOC="$DIR/sources/boot.wim" - [ ! -f "$LOC" ] && LOC="$DIR/sources/boot.esd" - - if [ -f "$LOC" ]; then - - MSG="Adding XML file for automatic installation..." - info "$MSG" && html "$MSG" - - RESULT=$(wimlib-imagex info -xml "$LOC" | tr -d '\000') - - if [[ "${RESULT^^}" == *""* ]]; then - INDEX="2" - else - INDEX="1" - fi - - wimlib-imagex update "$LOC" "$INDEX" --command "add $ASSET /autounattend.xml" > /dev/null + EXTERNAL="Y" + BASE="$CUSTOM" else - ASSET="" - warn "failed to locate 'boot.wim' or 'boot.esd' in ISO image, $FB" + CUSTOM="" + + if [[ "${VERSION,,}" == "http"* ]]; then + EXTERNAL="Y" + else + EXTERNAL="N" + fi + + if [[ "$EXTERNAL" != [Yy1]* ]]; then + + BASE="$VERSION.iso" + + if ! skipInstall && [ ! -f "$STORAGE/$BASE" ]; then + msg="Windows is being downloaded, please wait..." + fi + + else + + BASE=$(basename "${VERSION%%\?*}") + : "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}" + BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g') + + if ! skipInstall && [ ! -f "$STORAGE/$BASE" ]; then + msg="Image '$BASE' is being downloaded, please wait..." + fi + + fi + + [[ "${BASE,,}" == "custom."* ]] && BASE="windows.iso" fi + + html "$msg" + + [ -z "$MANUAL" ] && MANUAL="N" + + if [ -f "$STORAGE/$BASE" ]; then + + # Check if the ISO was already processed by our script + local magic=$(dd if="$STORAGE/$BASE" seek=0 bs=1 count=1 status=none | tr -d '\000') + magic="$(printf '%s' "$magic" | od -A n -t x1 -v | tr -d ' \n')" + + if [[ "$magic" == "16" ]]; then + + if hasDisk || [[ "$MANUAL" = [Yy1]* ]]; then + return 1 + fi + + fi + + EXTERNAL="Y" + CUSTOM="$BASE" + + else + + if skipInstall; then + BASE="" + return 1 + fi + + fi + + mkdir -p "$TMP" + + if [ ! -f "$STORAGE/$CUSTOM" ]; then + CUSTOM="" + ISO="$TMP/$BASE" + else + ISO="$STORAGE/$CUSTOM" + fi + + rm -f "$TMP/$BASE" + return 0 +} + +downloadImage() { + + local iso="$1" + local url="$2" + local progress + rm -f "$iso" + + if [[ "$EXTERNAL" != [Yy1]* ]]; then + + cd "$TMP" + /run/mido.sh "$url" + cd /run + + [ ! -f "$iso" ] && error "Failed to download $url" && exit 61 + return 0 + + fi + + info "Downloading $BASE as boot image..." + + # Check if running with interactive TTY or redirected to docker log + if [ -t 1 ]; then + progress="--progress=bar:noscroll" + else + progress="--progress=dot:giga" + fi + + { wget "$url" -O "$iso" -q --no-check-certificate --show-progress "$progress"; rc=$?; } || : + + (( rc != 0 )) && error "Failed to download $url, reason: $rc" && exit 60 + [ ! -f "$iso" ] && error "Failed to download $url" && exit 61 + + return 0 +} + +extractImage() { + + local iso="$1" + local dir="$2" + + local msg="Extracting downloaded ISO image..." + [ -n "$CUSTOM" ] && msg="Extracting local ISO image..." + info "$msg" && html "$msg" + + local size=$(stat -c%s "$iso") + local size_gb=$(( (size + 1073741823)/1073741824 )) + local space=$(df --output=avail -B 1 "$TMP" | tail -n 1) + local space_gb=$(( (space + 1073741823)/1073741824 )) + + if ((size<10000000)); then + error "Invalid ISO file: Size is smaller than 10 MB" && exit 62 + fi + + if (( size > space )); then + error "Not enough free space in $STORAGE, have $space_gb GB available but need at least $size_gb GB." && exit 63 + fi + + rm -rf "$dir" + 7z x "$iso" -o"$dir" > /dev/null + + if [ ! -f "$dir/$ETFS" ] || [ ! -f "$dir/$EFISYS" ]; then + + if [ ! -f "$dir/$ETFS" ]; then + warn "failed to locate file 'etfsboot.com' in ISO image, $FB" + else + warn "failed to locate file 'efisys_noprompt.bin' in ISO image, $FB" + fi + + return 1 + fi + + [ -z "$CUSTOM" ] && rm -f "$iso" + + return 0 +} + +findVersion() { + + local name="$1" + local detected="" + + [[ "${name,,}" == *"windows 11"* ]] && detected="win11x64" + [[ "${name,,}" == *"windows 10"* ]] && detected="win10x64" + [[ "${name,,}" == *"windows 8"* ]] && detected="win81x64" + [[ "${name,,}" == *"server 2022"* ]] && detected="win2022-eval" + [[ "${name,,}" == *"server 2019"* ]] && detected="win2019-eval" + [[ "${name,,}" == *"server 2016"* ]] && detected="win2016-eval" + + echo "$detected" + return 0 +} + +selectXML() { + + local dir="$1" + + XML="" + [[ "$MANUAL" == [Yy1]* ]] && return 0 + + if [[ "$EXTERNAL" != [Yy1]* ]] && [ -z "$CUSTOM" ]; then + XML="$VERSION.xml" + [ -f "/run/assets/$XML" ] && return 0 + fi + + info "Detecting Windows version from ISO image..." + + local loc="$dir/sources/install.wim" + [ ! -f "$loc" ] && loc="$dir/sources/install.esd" + + if [ ! -f "$loc" ]; then + warn "failed to locate 'install.wim' or 'install.esd' in ISO image, $FB" + return 0 + fi + + local tag="DISPLAYNAME" + local result=$(wimlib-imagex info -xml "$loc" | tr -d '\000') + local name=$(sed -n "/$tag/{s/.*<$tag>\(.*\)<\/$tag>.*/\1/;p}" <<< "$result") + local detected=$(findVersion "$name") + + if [ -z "$detected" ]; then + + tag="PRODUCTNAME" + local name2=$(sed -n "/$tag/{s/.*<$tag>\(.*\)<\/$tag>.*/\1/;p}" <<< "$result") + [ -z "$name" ] && name="$name2" + detected=$(findVersion "$name2") + + fi + + if [ -n "$detected" ]; then + + if [ -f "/run/assets/$detected.xml" ]; then + XML="$detected.xml" + echo "Detected image of type '$detected', which supports automatic installation." + else + warn "detected image of type '$detected', but no matching XML file exists, $FB." + fi + + else + + if [ -z "$name" ]; then + warn "failed to detect Windows version from image, $FB" + else + if [[ "${name,,}" == "windows 7" ]]; then + warn "detected Windows 7 image, $FB" + else + warn "failed to detect Windows version from string '$name', $FB" + fi + fi + + fi + + return 0 +} + +updateImage() { + + local dir="$1" + local asset="$2" + + [ ! -f "$asset" ] && return 0 + replaceXML "$dir" "$asset" + + local loc="$dir/sources/boot.wim" + [ ! -f "$loc" ] && loc="$dir/sources/boot.esd" + + if [ ! -f "$loc" ]; then + warn "failed to locate 'boot.wim' or 'boot.esd' in ISO image, $FB" + return 0 + fi + + info "Adding XML file for automatic installation..." + + local index="1" + local result=$(wimlib-imagex info -xml "$loc" | tr -d '\000') + + if [[ "${result^^}" == *""* ]]; then + index="2" + fi + + wimlib-imagex update "$loc" "$index" --command "add $asset /autounattend.xml" > /dev/null + + return 0 +} + +buildImage() { + + local dir="$1" + local cat="BOOT.CAT" + local label="${BASE%.*}" + label="${label::30}" + local out="$TMP/$label.tmp" + rm -f "$out" + + local msg="Generating updated ISO image..." + info "$msg" && html "$msg" + + local size=$(du -h -b --max-depth=0 "$dir" | cut -f1) + local size_gb=$(( (size + 1073741823)/1073741824 )) + local space=$(df --output=avail -B 1 "$TMP" | tail -n 1) + local space_gb=$(( (space + 1073741823)/1073741824 )) + + if (( size > space )); then + error "Not enough free space in $STORAGE, have $space_gb GB available but need at least $size_gb GB." && exit 63 + fi + + genisoimage -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 4 -J -l -D -N -joliet-long -relaxed-filenames -quiet -V "$label" -udf \ + -boot-info-table -eltorito-alt-boot -eltorito-boot "$EFISYS" -no-emul-boot -o "$out" -allow-limited-size "$dir" + + [ -n "$CUSTOM" ] && rm -f "$STORAGE/$CUSTOM" + + if [ -f "$STORAGE/$BASE" ]; then + error "File $STORAGE/$BASE does already exist ?!" && exit 64 + fi + + mv "$out" "$STORAGE/$BASE" + return 0 +} + +###################################### + +if ! startInstall; then + rm -rf "$TMP" + return 0 fi -CAT="BOOT.CAT" -LABEL="${BASE%.*}" -LABEL="${LABEL::30}" -OUT="$TMP/$LABEL.tmp" -rm -f "$OUT" - -SPACE=$(df --output=avail -B 1 "$TMP" | tail -n 1) -SPACE_GB=$(( (SPACE + 1073741823)/1073741824 )) - -if (( SIZE > SPACE )); then - error "Not enough free space in $STORAGE, have $SPACE_GB GB available but need at least $SIZE_GB GB." && exit 63 +if [ ! -f "$ISO" ]; then + downloadImage "$ISO" "$VERSION" fi -MSG="Generating the ISO image..." -info "$MSG" && html "$MSG" +if ! extractImage "$ISO" "$DIR"; then -genisoimage -b "$ETFS" -no-emul-boot -c "$CAT" -iso-level 4 -J -l -D -N -joliet-long -relaxed-filenames -quiet -V "$LABEL" -udf \ - -boot-info-table -eltorito-alt-boot -eltorito-boot "$EFISYS" -no-emul-boot -o "$OUT" -allow-limited-size "$DIR" + if [[ "$ISO" != "$STORAGE/$BASE" ]]; then + mv -f "$ISO" "$STORAGE/$BASE" + fi -# Mark ISO as prepared via magic byte -printf '\x16' | dd of="$OUT" bs=1 seek=0 count=1 conv=notrunc status=none + finishInstall "$STORAGE/$BASE" + return 0 -[ -n "$CUSTOM" ] && rm -f "$STORAGE/$CUSTOM" - -if [ -f "$STORAGE/$BASE" ]; then - error "File $STORAGE/$BASE does already exist ?!" && exit 64 fi -mv "$OUT" "$STORAGE/$BASE" +selectXML "$DIR" -rm -f "$STORAGE/windows.ver" -cp /run/version "$STORAGE/windows.ver" +updateImage "$DIR" "/run/assets/$XML" -rm -rf "$TMP" +buildImage "$DIR" + +finishInstall "$STORAGE/$BASE" html "Successfully prepared image for installation..." - return 0 diff --git a/src/power.sh b/src/power.sh index 75e244b..32cccf1 100644 --- a/src/power.sh +++ b/src/power.sh @@ -7,6 +7,7 @@ QEMU_TERM="" QEMU_PORT=7100 QEMU_TIMEOUT=110 QEMU_PID="/run/shm/qemu.pid" +QEMU_PTY="/run/shm/qemu.pty" QEMU_LOG="/run/shm/qemu.log" QEMU_OUT="/run/shm/qemu.out" QEMU_END="/run/shm/qemu.end" @@ -29,7 +30,7 @@ finish() { if [ -f "$QEMU_PID" ]; then pid=$(<"$QEMU_PID") - echo && error "Forcefully terminating Windows, reason: $reason..." + error "Forcefully terminating Windows, reason: $reason..." { kill -15 "$pid" || true; } 2>/dev/null while isAlive "$pid"; do @@ -44,8 +45,8 @@ finish() { closeNetwork - sleep 1 - echo && echo "❯ Shutdown completed!" + sleep 0.5 + echo "❯ Shutdown completed!" exit "$reason" } @@ -95,15 +96,15 @@ _graceful_shutdown() { set +e if [ -f "$QEMU_END" ]; then - echo && info "Received $1 while already shutting down..." + info "Received $1 while already shutting down..." return fi touch "$QEMU_END" - echo && info "Received $1, sending ACPI shutdown signal..." + info "Received $1, sending ACPI shutdown signal..." if [ ! -f "$QEMU_PID" ]; then - echo && error "QEMU PID file does not exist?" + error "QEMU PID file does not exist?" finish "$code" && return "$code" fi @@ -111,10 +112,22 @@ _graceful_shutdown() { pid=$(<"$QEMU_PID") if ! isAlive "$pid"; then - echo && error "QEMU process does not exist?" + error "QEMU process does not exist?" finish "$code" && return "$code" fi + if [ ! f "$STORAGE/windows.boot" ] && [ -f "$QEMU_PTY" ]; then + if ! grep -Fq "Windows Boot Manager" "$QEMU_PTY"; then + info "Cannot send ACPI signal during Windows setup, aborting..." + finish "$code" && return "$code" + else + if [ -f "$STORAGE/$BASE" ]; then + rm -f "$STORAGE/$BASE" + touch "$STORAGE/windows.boot" + fi + fi + fi + # Send ACPI shutdown signal echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_PORT}" > /dev/null @@ -136,7 +149,7 @@ _graceful_shutdown() { done if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then - echo && error "Shutdown timeout reached, aborting..." + error "Shutdown timeout reached, aborting..." fi finish "$code" && return "$code"