mirror of
https://github.com/dockur/windows.git
synced 2025-10-27 19:35:49 +00:00
Merge branch 'gytsto/improve-qemu-guest-agent-script' into 'master'
improve qga.py See merge request low-level-hacks/third-party-build/dockur_windows!7
This commit is contained in:
commit
1e26f832ed
8 changed files with 235 additions and 29 deletions
|
|
@ -9,6 +9,7 @@
|
||||||
<SystemLocale>en-US</SystemLocale>
|
<SystemLocale>en-US</SystemLocale>
|
||||||
<UILanguage>en-US</UILanguage>
|
<UILanguage>en-US</UILanguage>
|
||||||
<UserLocale>en-US</UserLocale>
|
<UserLocale>en-US</UserLocale>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DiskConfiguration>
|
<DiskConfiguration>
|
||||||
|
|
@ -137,6 +138,7 @@
|
||||||
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
||||||
</OEMInformation>
|
</OEMInformation>
|
||||||
<OEMName>Windows for Docker</OEMName>
|
<OEMName>Windows for Docker</OEMName>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DisableWER>1</DisableWER>
|
<DisableWER>1</DisableWER>
|
||||||
|
|
@ -301,6 +303,7 @@
|
||||||
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
<UserAccounts>
|
<UserAccounts>
|
||||||
<LocalAccounts>
|
<LocalAccounts>
|
||||||
<LocalAccount wcm:action="add">
|
<LocalAccount wcm:action="add">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<SystemLocale>en-US</SystemLocale>
|
<SystemLocale>en-US</SystemLocale>
|
||||||
<UILanguage>en-US</UILanguage>
|
<UILanguage>en-US</UILanguage>
|
||||||
<UserLocale>en-US</UserLocale>
|
<UserLocale>en-US</UserLocale>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DiskConfiguration>
|
<DiskConfiguration>
|
||||||
|
|
@ -140,6 +141,7 @@
|
||||||
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
||||||
</OEMInformation>
|
</OEMInformation>
|
||||||
<OEMName>Windows for Docker</OEMName>
|
<OEMName>Windows for Docker</OEMName>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DisableWER>1</DisableWER>
|
<DisableWER>1</DisableWER>
|
||||||
|
|
@ -304,6 +306,7 @@
|
||||||
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
<UserAccounts>
|
<UserAccounts>
|
||||||
<LocalAccounts>
|
<LocalAccounts>
|
||||||
<LocalAccount wcm:action="add">
|
<LocalAccount wcm:action="add">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<SystemLocale>en-US</SystemLocale>
|
<SystemLocale>en-US</SystemLocale>
|
||||||
<UILanguage>en-US</UILanguage>
|
<UILanguage>en-US</UILanguage>
|
||||||
<UserLocale>en-US</UserLocale>
|
<UserLocale>en-US</UserLocale>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DiskConfiguration>
|
<DiskConfiguration>
|
||||||
|
|
@ -140,6 +141,7 @@
|
||||||
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
||||||
</OEMInformation>
|
</OEMInformation>
|
||||||
<OEMName>Windows for Docker</OEMName>
|
<OEMName>Windows for Docker</OEMName>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DisableWER>1</DisableWER>
|
<DisableWER>1</DisableWER>
|
||||||
|
|
@ -304,6 +306,7 @@
|
||||||
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
<UserAccounts>
|
<UserAccounts>
|
||||||
<LocalAccounts>
|
<LocalAccounts>
|
||||||
<LocalAccount wcm:action="add">
|
<LocalAccount wcm:action="add">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<SystemLocale>en-US</SystemLocale>
|
<SystemLocale>en-US</SystemLocale>
|
||||||
<UILanguage>en-US</UILanguage>
|
<UILanguage>en-US</UILanguage>
|
||||||
<UserLocale>en-US</UserLocale>
|
<UserLocale>en-US</UserLocale>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DiskConfiguration>
|
<DiskConfiguration>
|
||||||
|
|
@ -140,6 +141,7 @@
|
||||||
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
||||||
</OEMInformation>
|
</OEMInformation>
|
||||||
<OEMName>Windows for Docker</OEMName>
|
<OEMName>Windows for Docker</OEMName>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DisableWER>1</DisableWER>
|
<DisableWER>1</DisableWER>
|
||||||
|
|
@ -304,6 +306,7 @@
|
||||||
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
<UserAccounts>
|
<UserAccounts>
|
||||||
<LocalAccounts>
|
<LocalAccounts>
|
||||||
<LocalAccount wcm:action="add">
|
<LocalAccount wcm:action="add">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<SystemLocale>en-US</SystemLocale>
|
<SystemLocale>en-US</SystemLocale>
|
||||||
<UILanguage>en-US</UILanguage>
|
<UILanguage>en-US</UILanguage>
|
||||||
<UserLocale>en-US</UserLocale>
|
<UserLocale>en-US</UserLocale>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DiskConfiguration>
|
<DiskConfiguration>
|
||||||
|
|
@ -140,6 +141,7 @@
|
||||||
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
<SupportURL>https://github.com/dockur/windows/issues</SupportURL>
|
||||||
</OEMInformation>
|
</OEMInformation>
|
||||||
<OEMName>Windows for Docker</OEMName>
|
<OEMName>Windows for Docker</OEMName>
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<DisableWER>1</DisableWER>
|
<DisableWER>1</DisableWER>
|
||||||
|
|
@ -304,6 +306,7 @@
|
||||||
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
||||||
</component>
|
</component>
|
||||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<TimeZone>UTC</TimeZone>
|
||||||
<UserAccounts>
|
<UserAccounts>
|
||||||
<LocalAccounts>
|
<LocalAccounts>
|
||||||
<LocalAccount wcm:action="add">
|
<LocalAccount wcm:action="add">
|
||||||
|
|
|
||||||
161
src/boot.sh
Executable file
161
src/boot.sh
Executable file
|
|
@ -0,0 +1,161 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# Docker environment variables
|
||||||
|
: "${BIOS:=""}" # BIOS file
|
||||||
|
: "${TPM:="N"}" # Disable TPM
|
||||||
|
: "${SMM:="N"}" # Disable SMM
|
||||||
|
|
||||||
|
BOOT_DESC=""
|
||||||
|
BOOT_OPTS=""
|
||||||
|
|
||||||
|
SECURE="off"
|
||||||
|
[[ "$SMM" == [Yy1]* ]] && SECURE="on"
|
||||||
|
[ -n "$BIOS" ] && BOOT_MODE="custom"
|
||||||
|
|
||||||
|
case "${BOOT_MODE,,}" in
|
||||||
|
"uefi" | "" )
|
||||||
|
BOOT_MODE="uefi"
|
||||||
|
ROM="OVMF_CODE_4M.fd"
|
||||||
|
VARS="OVMF_VARS_4M.fd"
|
||||||
|
;;
|
||||||
|
"secure" )
|
||||||
|
SECURE="on"
|
||||||
|
BOOT_DESC=" securely"
|
||||||
|
ROM="OVMF_CODE_4M.secboot.fd"
|
||||||
|
VARS="OVMF_VARS_4M.secboot.fd"
|
||||||
|
;;
|
||||||
|
"windows" | "windows_plain" )
|
||||||
|
ROM="OVMF_CODE_4M.fd"
|
||||||
|
VARS="OVMF_VARS_4M.fd"
|
||||||
|
;;
|
||||||
|
"windows_secure" )
|
||||||
|
TPM="Y"
|
||||||
|
SECURE="on"
|
||||||
|
BOOT_DESC=" securely"
|
||||||
|
ROM="OVMF_CODE_4M.ms.fd"
|
||||||
|
VARS="OVMF_VARS_4M.ms.fd"
|
||||||
|
;;
|
||||||
|
"windows_legacy" )
|
||||||
|
HV="N"
|
||||||
|
SECURE="on"
|
||||||
|
BOOT_DESC=" (legacy)"
|
||||||
|
[ -z "${USB:-}" ] && USB="usb-ehci,id=ehci"
|
||||||
|
;;
|
||||||
|
"legacy" )
|
||||||
|
BOOT_DESC=" with SeaBIOS"
|
||||||
|
;;
|
||||||
|
"custom" )
|
||||||
|
BOOT_OPTS="-bios $BIOS"
|
||||||
|
BOOT_DESC=" with custom BIOS file"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "Unknown BOOT_MODE, value \"${BOOT_MODE}\" is not recognized!"
|
||||||
|
exit 33
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "${BOOT_MODE,,}" == "windows"* ]]; then
|
||||||
|
BOOT_OPTS+=" -rtc base=utc"
|
||||||
|
BOOT_OPTS+=" -global ICH9-LPC.disable_s3=1"
|
||||||
|
BOOT_OPTS+=" -global ICH9-LPC.disable_s4=1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${BOOT_MODE,,}" in
|
||||||
|
"uefi" | "secure" | "windows" | "windows_plain" | "windows_secure" )
|
||||||
|
|
||||||
|
OVMF="/usr/share/OVMF"
|
||||||
|
DEST="$STORAGE/${BOOT_MODE,,}"
|
||||||
|
|
||||||
|
if [ ! -s "$DEST.rom" ] || [ ! -f "$DEST.rom" ]; then
|
||||||
|
[ ! -s "$OVMF/$ROM" ] || [ ! -f "$OVMF/$ROM" ] && error "UEFI boot file ($OVMF/$ROM) not found!" && exit 44
|
||||||
|
cp "$OVMF/$ROM" "$DEST.rom"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -s "$DEST.vars" ] || [ ! -f "$DEST.vars" ]; then
|
||||||
|
[ ! -s "$OVMF/$VARS" ] || [ ! -f "$OVMF/$VARS" ]&& error "UEFI vars file ($OVMF/$VARS) not found!" && exit 45
|
||||||
|
cp "$OVMF/$VARS" "$DEST.vars"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${BOOT_MODE,,}" == "secure" ]] || [[ "${BOOT_MODE,,}" == "windows_secure" ]]; then
|
||||||
|
BOOT_OPTS+=" -global driver=cfi.pflash01,property=secure,value=on"
|
||||||
|
fi
|
||||||
|
|
||||||
|
BOOT_OPTS+=" -drive file=$DEST.rom,if=pflash,unit=0,format=raw,readonly=on"
|
||||||
|
BOOT_OPTS+=" -drive file=$DEST.vars,if=pflash,unit=1,format=raw"
|
||||||
|
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
MSRS="/sys/module/kvm/parameters/ignore_msrs"
|
||||||
|
if [ -e "$MSRS" ]; then
|
||||||
|
result=$(<"$MSRS")
|
||||||
|
result="${result//[![:print:]]/}"
|
||||||
|
if [[ "$result" == "0" ]] || [[ "${result^^}" == "N" ]]; then
|
||||||
|
echo 1 | tee "$MSRS" > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
CLOCKSOURCE="tsc"
|
||||||
|
[[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter"
|
||||||
|
CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource"
|
||||||
|
|
||||||
|
if [ ! -f "$CLOCK" ]; then
|
||||||
|
warn "file \"$CLOCK\" cannot not found?"
|
||||||
|
else
|
||||||
|
result=$(<"$CLOCK")
|
||||||
|
result="${result//[![:print:]]/}"
|
||||||
|
case "${result,,}" in
|
||||||
|
"${CLOCKSOURCE,,}" ) ;;
|
||||||
|
"kvm-clock" ) info "Nested KVM virtualization detected.." ;;
|
||||||
|
"hyperv_clocksource_tsc_page" ) info "Nested Hyper-V virtualization detected.." ;;
|
||||||
|
"hpet" ) warn "unsupported clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
|
||||||
|
*) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
SM_BIOS=""
|
||||||
|
PS="/sys/class/dmi/id/product_serial"
|
||||||
|
|
||||||
|
if [ -s "$PS" ] && [ -r "$PS" ]; then
|
||||||
|
|
||||||
|
BIOS_SERIAL=$(<"$PS")
|
||||||
|
BIOS_SERIAL="${BIOS_SERIAL//[![:alnum:]]/}"
|
||||||
|
|
||||||
|
if [ -n "$BIOS_SERIAL" ]; then
|
||||||
|
SM_BIOS="-smbios type=1,serial=$BIOS_SERIAL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$TPM" == [Yy1]* ]]; then
|
||||||
|
|
||||||
|
rm -f /var/run/tpm.pid
|
||||||
|
|
||||||
|
if ! swtpm socket -t -d --tpmstate "backend-uri=file://$STORAGE/${BOOT_MODE,,}.tpm" --ctrl type=unixio,path=/run/swtpm-sock --pid file=/var/run/tpm.pid --tpm2; then
|
||||||
|
error "Failed to start TPM emulator, reason: $?"
|
||||||
|
else
|
||||||
|
|
||||||
|
for (( i = 1; i < 20; i++ )); do
|
||||||
|
|
||||||
|
[ -S "/run/swtpm-sock" ] && break
|
||||||
|
|
||||||
|
if (( i % 10 == 0 )); then
|
||||||
|
echo "Waiting for TPM emulator to become available..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 0.1
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -S "/run/swtpm-sock" ]; then
|
||||||
|
error "TPM socket not found? Disabling TPM module..."
|
||||||
|
else
|
||||||
|
BOOT_OPTS+=" -chardev socket,id=chrtpm,path=/run/swtpm-sock"
|
||||||
|
BOOT_OPTS+=" -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
@ -1412,7 +1412,7 @@ prepareInstall() {
|
||||||
echo " OEMSkipRegional=1"
|
echo " OEMSkipRegional=1"
|
||||||
echo " OemSkipWelcome=1"
|
echo " OemSkipWelcome=1"
|
||||||
echo " AdminPassword=$password"
|
echo " AdminPassword=$password"
|
||||||
echo " TimeZone=0"
|
echo " TimeZone=85"
|
||||||
echo " AutoLogon=Yes"
|
echo " AutoLogon=Yes"
|
||||||
echo " AutoLogonCount=65432"
|
echo " AutoLogonCount=65432"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
86
src/qga.py
86
src/qga.py
|
|
@ -29,58 +29,61 @@ def decode_output(data):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try Hex decoding first
|
|
||||||
return bytes.fromhex(data).decode("utf-8", errors="ignore")
|
return bytes.fromhex(data).decode("utf-8", errors="ignore")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# If hex fails, try Base64 decoding
|
|
||||||
return base64.b64decode(data).decode("utf-8", errors="ignore")
|
return base64.b64decode(data).decode("utf-8", errors="ignore")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# If all decoding fails, return raw
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def execute_command(sock, command_path, command_args):
|
def execute_command(sock, command_path, command_args, timeout):
|
||||||
"""Execute a command inside the guest VM with specified path and arguments."""
|
"""Execute a command inside the guest VM with specified path and arguments."""
|
||||||
exec_request = {
|
exec_request = {
|
||||||
"execute": "guest-exec",
|
"execute": "guest-exec",
|
||||||
"arguments": {
|
"arguments": {
|
||||||
"path": command_path,
|
"path": command_path,
|
||||||
"arg": command_args,
|
"arg": command_args,
|
||||||
"capture-output": True, # Capture stdout and stderr
|
"capture-output": True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print(f"Executing: {command_path} {' '.join(command_args)}")
|
||||||
response = send_qga_command(sock, exec_request)
|
response = send_qga_command(sock, exec_request)
|
||||||
|
|
||||||
if response is None:
|
if response is None or "return" not in response or "pid" not in response["return"]:
|
||||||
return None
|
print(
|
||||||
|
"Error: Failed to start execution.",
|
||||||
if "return" not in response or "pid" not in response["return"]:
|
json.dumps(response or {}, indent=2),
|
||||||
print("Error: Failed to start execution:", response, file=sys.stderr)
|
file=sys.stderr,
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
pid = response["return"]["pid"]
|
pid = response["return"]["pid"]
|
||||||
print(f"Command started with PID {pid}")
|
print(f"Command started with PID {pid}")
|
||||||
|
|
||||||
# Step 2: Wait for completion
|
# Step 2: Wait for completion with timeout
|
||||||
|
start_time = time.time()
|
||||||
|
status = {}
|
||||||
while True:
|
while True:
|
||||||
|
if time.time() - start_time > timeout:
|
||||||
|
print("Execution timeout reached.", file=sys.stderr)
|
||||||
|
return {"exit_code": -2, "stdout": "", "stderr": "Execution timed out."}
|
||||||
|
|
||||||
status_request = {"execute": "guest-exec-status", "arguments": {"pid": pid}}
|
status_request = {"execute": "guest-exec-status", "arguments": {"pid": pid}}
|
||||||
status_response = send_qga_command(sock, status_request)
|
status_response = send_qga_command(sock, status_request)
|
||||||
|
|
||||||
if status_response is None:
|
if status_response and "return" in status_response:
|
||||||
continue
|
|
||||||
|
|
||||||
if "return" in status_response:
|
|
||||||
status = status_response["return"]
|
status = status_response["return"]
|
||||||
if status.get("exited", False):
|
if status.get("exited", False):
|
||||||
break # Command finished
|
break
|
||||||
time.sleep(0.2) # Wait before checking again
|
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
# Step 3: Get exit code and output
|
|
||||||
exit_code = status.get("exitcode", -1)
|
exit_code = status.get("exitcode", -1)
|
||||||
stdout_data = decode_output(status.get("out-data", ""))
|
stdout_data = decode_output(status.get("out-data", ""))
|
||||||
stderr_data = decode_output(status.get("err-data", ""))
|
stderr_data = decode_output(status.get("err-data", ""))
|
||||||
|
|
@ -91,7 +94,7 @@ def execute_command(sock, command_path, command_args):
|
||||||
def create_socket():
|
def create_socket():
|
||||||
"""Create and return a reusable socket connection to the QEMU Guest Agent."""
|
"""Create and return a reusable socket connection to the QEMU Guest Agent."""
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
sock.settimeout(30) # 30 seconds timeout
|
sock.settimeout(30)
|
||||||
try:
|
try:
|
||||||
sock.connect(QGA_SOCKET)
|
sock.connect(QGA_SOCKET)
|
||||||
return sock
|
return sock
|
||||||
|
|
@ -103,6 +106,21 @@ def create_socket():
|
||||||
def parse_args():
|
def parse_args():
|
||||||
"""Parse command-line arguments."""
|
"""Parse command-line arguments."""
|
||||||
parser = argparse.ArgumentParser(description="Send commands to QEMU Guest Agent.")
|
parser = argparse.ArgumentParser(description="Send commands to QEMU Guest Agent.")
|
||||||
|
shell_group = parser.add_mutually_exclusive_group()
|
||||||
|
shell_group.add_argument(
|
||||||
|
"--cmd", action="store_true", help="Run the command through cmd.exe /c"
|
||||||
|
)
|
||||||
|
shell_group.add_argument(
|
||||||
|
"--powershell",
|
||||||
|
action="store_true",
|
||||||
|
help="Run the command with powershell -Command",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--timeout", type=int, default=60, help="Max execution time in seconds"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--json", action="store_true", help="Output result in JSON format"
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"command", help="Path to the command to execute inside the guest VM"
|
"command", help="Path to the command to execute inside the guest VM"
|
||||||
)
|
)
|
||||||
|
|
@ -113,23 +131,35 @@ def parse_args():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Parse command-line arguments
|
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|
||||||
# Create a reusable socket
|
if args.cmd:
|
||||||
|
command_path = "cmd.exe"
|
||||||
|
command_args = ["/c", args.command] + args.args
|
||||||
|
elif args.powershell:
|
||||||
|
command_path = "powershell.exe"
|
||||||
|
full_command = " ".join([args.command] + args.args)
|
||||||
|
command_args = ["-Command", full_command]
|
||||||
|
else:
|
||||||
|
command_path = args.command
|
||||||
|
command_args = args.args
|
||||||
|
|
||||||
|
# Create a reusable socket
|
||||||
unix_sock = create_socket()
|
unix_sock = create_socket()
|
||||||
if not unix_sock:
|
if not unix_sock:
|
||||||
print("Failed to create socket.", file=sys.stderr)
|
print("Failed to create socket.", file=sys.stderr)
|
||||||
sys.exit(1) # Exit if we can't connect to the socket
|
sys.exit(1) # Exit if we can't connect to the socket
|
||||||
|
|
||||||
# Execute the command
|
result = execute_command(unix_sock, command_path, command_args, args.timeout)
|
||||||
result = execute_command(unix_sock, args.command, args.args)
|
|
||||||
if result:
|
if result:
|
||||||
print(f"Exit Code: {result['exit_code']}")
|
if args.json:
|
||||||
if result["stdout"]:
|
print(json.dumps(result, indent=2))
|
||||||
print("STDOUT:\n", result["stdout"])
|
else:
|
||||||
if result["stderr"]:
|
print(f"Exit Code: {result['exit_code']}")
|
||||||
print("STDERR:\n", result["stderr"])
|
if result["stdout"]:
|
||||||
|
print("STDOUT:\n", result["stdout"])
|
||||||
|
if result["stderr"]:
|
||||||
|
print("STDERR:\n", result["stderr"])
|
||||||
|
|
||||||
# Close the socket once all commands are executed
|
# Close the socket once all commands are executed
|
||||||
unix_sock.close()
|
unix_sock.close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue