mirror of
https://github.com/qemu/qemu.git
synced 2025-08-16 14:54:29 +00:00
qemu-ga patch queue
* add config file dump/load support for qemu-ga * various w32 build fixes, particularly WRT to msi package creation * fixes for msi installer * w32 support for guest-set-user-password v2: * replaced g_list_free_full with g_list_foreach to maintain glib 2.22 compatibility -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJV5e+nAAoJEDNTyc7xCLWE48EIAIdYAp5cV9z6r0gCO0BfqSGX NPGorDZBY2zG3VzhRdYQPVGSbuMoYIwqM7TyDX4ZWg7AYCpciM3W9tLx33TeLxnd HWLP24ZywFIJWOviPdPV5pxVW1hyWA5nlnP+mfWBO/YDvNDsaZVIXhCWOUkwA/pd sO3UKMvM3Tn6rmxKzfX3LDXpRnL69xkrt39pO1/VZRkMVJQKVh9iSlERLlGQZdKw NxxsIJqFlTnTI98CrWlxmshQyToYVBdU1hmODhkytjWv0n+Wo8ABsHBB1LQYwPkc JmMwwkMsm0XpNojM6kD858SLUlmFRjfcaK0mTvbWX/5VUSPhJlg/T9bNjY8ekVA= =Aq6K -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mdroth/tags/qga-pull-2015-09-01-v2-tag' into staging qemu-ga patch queue * add config file dump/load support for qemu-ga * various w32 build fixes, particularly WRT to msi package creation * fixes for msi installer * w32 support for guest-set-user-password v2: * replaced g_list_free_full with g_list_foreach to maintain glib 2.22 compatibility # gpg: Signature made Tue 01 Sep 2015 19:34:15 BST using RSA key ID F108B584 # gpg: Good signature from "Michael Roth <flukshun@gmail.com>" # gpg: aka "Michael Roth <mdroth@utexas.edu>" # gpg: aka "Michael Roth <mdroth@linux.vnet.ibm.com>" * remotes/mdroth/tags/qga-pull-2015-09-01-v2-tag: (26 commits) Makefile: qemu-ga: fix msi target error message build: qemu-ga: fix VSS dependencies configure: qemu-ga: explicitly enable qemu-ga MSI support when probed configure: qemu-ga: move MSI installer probe after qga probe qemu-ga: implement win32 guest-set-user-password qga: start a man page qga: add --dump-conf option qga: add an optional qemu-ga.conf system configuration qga: free a bit more qga: move agent run in a separate function qga: fill default options in main() qga: move option parsing to separate function qga: copy argument strings qga: rename 'path' to 'channel_path' qga: make split_list() return allocated strings qga: move string split in separate function qga: use exit() when parsing options qga: misc spelling configure: qemu-ga: report MSI install support in summary qemu-ga: Fixed paths issue with MSI build ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
f8b8091d27
1
.gitignore
vendored
1
.gitignore
vendored
@ -58,6 +58,7 @@
|
|||||||
*.cp
|
*.cp
|
||||||
*.dvi
|
*.dvi
|
||||||
*.exe
|
*.exe
|
||||||
|
*.msi
|
||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.mo
|
*.mo
|
||||||
|
33
Makefile
33
Makefile
@ -88,7 +88,8 @@ LIBS+=-lz $(LIBS_TOOLS)
|
|||||||
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
|
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
|
||||||
|
|
||||||
ifdef BUILD_DOCS
|
ifdef BUILD_DOCS
|
||||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qmp-commands.txt
|
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
||||||
|
DOCS+=qmp-commands.txt
|
||||||
ifdef CONFIG_LINUX
|
ifdef CONFIG_LINUX
|
||||||
DOCS+=kvm_stat.1
|
DOCS+=kvm_stat.1
|
||||||
endif
|
endif
|
||||||
@ -289,28 +290,27 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
|||||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
||||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||||
|
|
||||||
qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a
|
# we require QGA_VSS_PROVIDER files to be built alongside qemu-ga
|
||||||
$(call LINK, $^)
|
# executable since they are shipped together, but we don't want to actually
|
||||||
|
# link against them
|
||||||
|
qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a $(QGA_VSS_PROVIDER)
|
||||||
|
$(call LINK, $(filter-out $(QGA_VSS_PROVIDER), $^))
|
||||||
|
|
||||||
ifdef QEMU_GA_MSI_ENABLED
|
ifdef QEMU_GA_MSI_ENABLED
|
||||||
QEMU_GA_MSI=qemu-ga-$(ARCH).msi
|
QEMU_GA_MSI=qemu-ga-$(ARCH).msi
|
||||||
|
|
||||||
msi: ${QEMU_GA_MSI}
|
msi: $(QEMU_GA_MSI)
|
||||||
|
|
||||||
$(QEMU_GA_MSI): qemu-ga.exe
|
$(QEMU_GA_MSI): qemu-ga.exe
|
||||||
|
|
||||||
ifdef QEMU_GA_MSI_WITH_VSS
|
|
||||||
$(QEMU_GA_MSI): qga/vss-win32/qga-vss.dll
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(QEMU_GA_MSI): config-host.mak
|
$(QEMU_GA_MSI): config-host.mak
|
||||||
|
|
||||||
$(QEMU_GA_MSI): qga/installer/qemu-ga.wxs
|
$(QEMU_GA_MSI): $(SRC_PATH)/qga/installer/qemu-ga.wxs
|
||||||
$(call quiet-command,QEMU_GA_VERSION="$(QEMU_GA_VERSION)" QEMU_GA_MANUFACTURER="$(QEMU_GA_MANUFACTURER)" QEMU_GA_DISTRO="$(QEMU_GA_DISTRO)" \
|
$(call quiet-command,QEMU_GA_VERSION="$(QEMU_GA_VERSION)" QEMU_GA_MANUFACTURER="$(QEMU_GA_MANUFACTURER)" QEMU_GA_DISTRO="$(QEMU_GA_DISTRO)" BUILD_DIR="$(BUILD_DIR)" \
|
||||||
wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<, " WIXL $@")
|
wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<, " WIXL $@")
|
||||||
else
|
else
|
||||||
msi:
|
msi:
|
||||||
@echo MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)
|
@echo "MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@ -400,6 +400,9 @@ ifneq ($(TOOLS),)
|
|||||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
|
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
|
||||||
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
||||||
endif
|
endif
|
||||||
|
ifneq (,$(findstring qemu-ga,$(TOOLS)))
|
||||||
|
$(INSTALL_DATA) qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
ifdef CONFIG_VIRTFS
|
ifdef CONFIG_VIRTFS
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||||
@ -538,6 +541,12 @@ qemu-nbd.8: qemu-nbd.texi
|
|||||||
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
|
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
|
||||||
" GEN $@")
|
" GEN $@")
|
||||||
|
|
||||||
|
qemu-ga.8: qemu-ga.texi
|
||||||
|
$(call quiet-command, \
|
||||||
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-ga.pod && \
|
||||||
|
$(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \
|
||||||
|
" GEN $@")
|
||||||
|
|
||||||
kvm_stat.1: scripts/kvm/kvm_stat.texi
|
kvm_stat.1: scripts/kvm/kvm_stat.texi
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< kvm_stat.pod && \
|
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< kvm_stat.pod && \
|
||||||
@ -551,7 +560,7 @@ pdf: qemu-doc.pdf qemu-tech.pdf
|
|||||||
|
|
||||||
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
||||||
qemu-img.texi qemu-nbd.texi qemu-options.texi \
|
qemu-img.texi qemu-nbd.texi qemu-options.texi \
|
||||||
qemu-monitor.texi qemu-img-cmds.texi
|
qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi
|
||||||
|
|
||||||
ifdef CONFIG_WIN32
|
ifdef CONFIG_WIN32
|
||||||
|
|
||||||
|
122
configure
vendored
122
configure
vendored
@ -732,7 +732,7 @@ if test "$mingw32" = "yes" ; then
|
|||||||
sysconfdir="\${prefix}"
|
sysconfdir="\${prefix}"
|
||||||
local_statedir=
|
local_statedir=
|
||||||
confsuffix=""
|
confsuffix=""
|
||||||
libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi $libs_qga"
|
libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi -lnetapi32 $libs_qga"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
werror=""
|
werror=""
|
||||||
@ -3851,6 +3851,7 @@ EOF
|
|||||||
guest_agent_with_vss="yes"
|
guest_agent_with_vss="yes"
|
||||||
QEMU_CFLAGS="$QEMU_CFLAGS $vss_win32_include"
|
QEMU_CFLAGS="$QEMU_CFLAGS $vss_win32_include"
|
||||||
libs_qga="-lole32 -loleaut32 -lshlwapi -luuid -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga"
|
libs_qga="-lole32 -loleaut32 -lshlwapi -luuid -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga"
|
||||||
|
qga_vss_provider="qga/vss-win32/qga-vss.dll qga/vss-win32/qga-vss.tlb"
|
||||||
else
|
else
|
||||||
if test "$vss_win32_sdk" != "" ; then
|
if test "$vss_win32_sdk" != "" ; then
|
||||||
echo "ERROR: Please download and install Microsoft VSS SDK:"
|
echo "ERROR: Please download and install Microsoft VSS SDK:"
|
||||||
@ -3904,58 +3905,6 @@ EOF
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
##########################################
|
|
||||||
# Guest agent Window MSI package
|
|
||||||
|
|
||||||
if test "$guest_agent" != yes; then
|
|
||||||
if test "$guest_agent_msi" = yes; then
|
|
||||||
error_exit "MSI guest agent package requires guest agent enabled"
|
|
||||||
fi
|
|
||||||
guest_agent_msi=no
|
|
||||||
elif test "$mingw32" != "yes"; then
|
|
||||||
if test "$guest_agent_msi" = "yes"; then
|
|
||||||
error_exit "MSI guest agent package is available only for MinGW Windows cross-compilation"
|
|
||||||
fi
|
|
||||||
guest_agent_msi=no
|
|
||||||
elif ! has wixl; then
|
|
||||||
if test "$guest_agent_msi" = "yes"; then
|
|
||||||
error_exit "MSI guest agent package requires wixl tool installed ( usually from msitools package )"
|
|
||||||
fi
|
|
||||||
guest_agent_msi=no
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$guest_agent_msi" != "no"; then
|
|
||||||
if test "$guest_agent_with_vss" = "yes"; then
|
|
||||||
QEMU_GA_MSI_WITH_VSS="-D InstallVss"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$QEMU_GA_MANUFACTURER" = ""; then
|
|
||||||
QEMU_GA_MANUFACTURER=QEMU
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$QEMU_GA_DISTRO" = ""; then
|
|
||||||
QEMU_GA_DISTRO=Linux
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$QEMU_GA_VERSION" = ""; then
|
|
||||||
QEMU_GA_VERSION=`cat $source_path/VERSION`
|
|
||||||
fi
|
|
||||||
|
|
||||||
QEMU_GA_MSI_MINGW_DLL_PATH="-D Mingw_dlls=`$pkg_config --variable=prefix glib-2.0`/bin"
|
|
||||||
|
|
||||||
case "$cpu" in
|
|
||||||
x86_64)
|
|
||||||
QEMU_GA_MSI_ARCH="-a x64 -D Arch=64"
|
|
||||||
;;
|
|
||||||
i386)
|
|
||||||
QEMU_GA_MSI_ARCH="-D Arch=32"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
error_exit "CPU $cpu not supported for building installation package"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# check if we have fdatasync
|
# check if we have fdatasync
|
||||||
|
|
||||||
@ -4396,12 +4345,12 @@ if test "$softmmu" = yes ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Probe for guest agent support/options
|
||||||
|
|
||||||
if [ "$guest_agent" != "no" ]; then
|
if [ "$guest_agent" != "no" ]; then
|
||||||
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
|
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
|
||||||
tools="qemu-ga\$(EXESUF) $tools"
|
tools="qemu-ga\$(EXESUF) $tools"
|
||||||
if [ "$mingw32" = "yes" -a "$guest_agent_with_vss" = "yes" ]; then
|
|
||||||
tools="qga/vss-win32/qga-vss.dll qga/vss-win32/qga-vss.tlb $tools"
|
|
||||||
fi
|
|
||||||
guest_agent=yes
|
guest_agent=yes
|
||||||
elif [ "$guest_agent" != yes ]; then
|
elif [ "$guest_agent" != yes ]; then
|
||||||
guest_agent=no
|
guest_agent=no
|
||||||
@ -4410,6 +4359,63 @@ if [ "$guest_agent" != "no" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Guest agent Window MSI package
|
||||||
|
|
||||||
|
if test "$guest_agent" != yes; then
|
||||||
|
if test "$guest_agent_msi" = yes; then
|
||||||
|
error_exit "MSI guest agent package requires guest agent enabled"
|
||||||
|
fi
|
||||||
|
guest_agent_msi=no
|
||||||
|
elif test "$mingw32" != "yes"; then
|
||||||
|
if test "$guest_agent_msi" = "yes"; then
|
||||||
|
error_exit "MSI guest agent package is available only for MinGW Windows cross-compilation"
|
||||||
|
fi
|
||||||
|
guest_agent_msi=no
|
||||||
|
elif ! has wixl; then
|
||||||
|
if test "$guest_agent_msi" = "yes"; then
|
||||||
|
error_exit "MSI guest agent package requires wixl tool installed ( usually from msitools package )"
|
||||||
|
fi
|
||||||
|
guest_agent_msi=no
|
||||||
|
else
|
||||||
|
# we support qemu-ga, mingw32, and wixl: default to MSI enabled if it wasn't
|
||||||
|
# disabled explicitly
|
||||||
|
if test "$guest_agent_msi" != "no"; then
|
||||||
|
guest_agent_msi=yes
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$guest_agent_msi" = "yes"; then
|
||||||
|
if test "$guest_agent_with_vss" = "yes"; then
|
||||||
|
QEMU_GA_MSI_WITH_VSS="-D InstallVss"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$QEMU_GA_MANUFACTURER" = ""; then
|
||||||
|
QEMU_GA_MANUFACTURER=QEMU
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$QEMU_GA_DISTRO" = ""; then
|
||||||
|
QEMU_GA_DISTRO=Linux
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$QEMU_GA_VERSION" = ""; then
|
||||||
|
QEMU_GA_VERSION=`cat $source_path/VERSION`
|
||||||
|
fi
|
||||||
|
|
||||||
|
QEMU_GA_MSI_MINGW_DLL_PATH="-D Mingw_dlls=`$pkg_config --variable=prefix glib-2.0`/bin"
|
||||||
|
|
||||||
|
case "$cpu" in
|
||||||
|
x86_64)
|
||||||
|
QEMU_GA_MSI_ARCH="-a x64 -D Arch=64"
|
||||||
|
;;
|
||||||
|
i386)
|
||||||
|
QEMU_GA_MSI_ARCH="-D Arch=32"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error_exit "CPU $cpu not supported for building installation package"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
# Mac OS X ships with a broken assembler
|
# Mac OS X ships with a broken assembler
|
||||||
roms=
|
roms=
|
||||||
if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
|
if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
|
||||||
@ -4577,6 +4583,7 @@ echo "libnfs support $libnfs"
|
|||||||
echo "build guest agent $guest_agent"
|
echo "build guest agent $guest_agent"
|
||||||
echo "QGA VSS support $guest_agent_with_vss"
|
echo "QGA VSS support $guest_agent_with_vss"
|
||||||
echo "QGA w32 disk info $guest_agent_ntddscsi"
|
echo "QGA w32 disk info $guest_agent_ntddscsi"
|
||||||
|
echo "QGA MSI support $guest_agent_msi"
|
||||||
echo "seccomp support $seccomp"
|
echo "seccomp support $seccomp"
|
||||||
echo "coroutine backend $coroutine"
|
echo "coroutine backend $coroutine"
|
||||||
echo "coroutine pool $coroutine_pool"
|
echo "coroutine pool $coroutine_pool"
|
||||||
@ -4651,12 +4658,13 @@ if test "$mingw32" = "yes" ; then
|
|||||||
echo "CONFIG_PRODUCTVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak
|
echo "CONFIG_PRODUCTVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak
|
||||||
if test "$guest_agent_with_vss" = "yes" ; then
|
if test "$guest_agent_with_vss" = "yes" ; then
|
||||||
echo "CONFIG_QGA_VSS=y" >> $config_host_mak
|
echo "CONFIG_QGA_VSS=y" >> $config_host_mak
|
||||||
|
echo "QGA_VSS_PROVIDER=$qga_vss_provider" >> $config_host_mak
|
||||||
echo "WIN_SDK=\"$win_sdk\"" >> $config_host_mak
|
echo "WIN_SDK=\"$win_sdk\"" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$guest_agent_ntddscsi" = "yes" ; then
|
if test "$guest_agent_ntddscsi" = "yes" ; then
|
||||||
echo "CONFIG_QGA_NTDDDISK=y" >> $config_host_mak
|
echo "CONFIG_QGA_NTDDDISK=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
if test "$guest_agent_msi" != "no"; then
|
if test "$guest_agent_msi" = "yes"; then
|
||||||
echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak
|
echo "QEMU_GA_MSI_ENABLED=yes" >> $config_host_mak
|
||||||
echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak
|
echo "QEMU_GA_MSI_MINGW_DLL_PATH=${QEMU_GA_MSI_MINGW_DLL_PATH}" >> $config_host_mak
|
||||||
echo "QEMU_GA_MSI_WITH_VSS=${QEMU_GA_MSI_WITH_VSS}" >> $config_host_mak
|
echo "QEMU_GA_MSI_WITH_VSS=${QEMU_GA_MSI_WITH_VSS}" >> $config_host_mak
|
||||||
|
@ -412,6 +412,7 @@ snapshots.
|
|||||||
* vm_snapshots:: VM snapshots
|
* vm_snapshots:: VM snapshots
|
||||||
* qemu_img_invocation:: qemu-img Invocation
|
* qemu_img_invocation:: qemu-img Invocation
|
||||||
* qemu_nbd_invocation:: qemu-nbd Invocation
|
* qemu_nbd_invocation:: qemu-nbd Invocation
|
||||||
|
* qemu_ga_invocation:: qemu-ga Invocation
|
||||||
* disk_images_formats:: Disk image file formats
|
* disk_images_formats:: Disk image file formats
|
||||||
* host_drives:: Using host drives
|
* host_drives:: Using host drives
|
||||||
* disk_images_fat_images:: Virtual FAT disk images
|
* disk_images_fat_images:: Virtual FAT disk images
|
||||||
@ -505,6 +506,11 @@ state is not saved or restored properly (in particular USB).
|
|||||||
|
|
||||||
@include qemu-nbd.texi
|
@include qemu-nbd.texi
|
||||||
|
|
||||||
|
@node qemu_ga_invocation
|
||||||
|
@subsection @code{qemu-ga} Invocation
|
||||||
|
|
||||||
|
@include qemu-ga.texi
|
||||||
|
|
||||||
@node disk_images_formats
|
@node disk_images_formats
|
||||||
@subsection Disk image file formats
|
@subsection Disk image file formats
|
||||||
|
|
||||||
|
137
qemu-ga.texi
Normal file
137
qemu-ga.texi
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
@example
|
||||||
|
@c man begin SYNOPSIS
|
||||||
|
usage: qemu-ga [OPTIONS]
|
||||||
|
@c man end
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@c man begin DESCRIPTION
|
||||||
|
|
||||||
|
The QEMU Guest Agent is a daemon intended to be run within virtual
|
||||||
|
machines. It allows the hypervisor host to perform various operations
|
||||||
|
in the guest, such as:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
get information from the guest
|
||||||
|
@item
|
||||||
|
set the guest's system time
|
||||||
|
@item
|
||||||
|
read/write a file
|
||||||
|
@item
|
||||||
|
sync and freeze the filesystems
|
||||||
|
@item
|
||||||
|
suspend the guest
|
||||||
|
@item
|
||||||
|
reconfigure guest local processors
|
||||||
|
@item
|
||||||
|
set user's password
|
||||||
|
@item
|
||||||
|
...
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
qemu-ga will read a system configuration file on startup (located at
|
||||||
|
q@file{/etc/qemu/qemu-ga.conf} by default), then parse remaining
|
||||||
|
configuration options on the command line. For the same key, the last
|
||||||
|
option wins, but the lists accumulate (see below for configuration
|
||||||
|
file format).
|
||||||
|
|
||||||
|
@c man end
|
||||||
|
|
||||||
|
@c man begin OPTIONS
|
||||||
|
@table @option
|
||||||
|
@item -m, --method=@var{method}
|
||||||
|
Transport method: one of @samp{unix-listen}, @samp{virtio-serial}, or
|
||||||
|
@samp{isa-serial} (@samp{virtio-serial} is the default).
|
||||||
|
|
||||||
|
@item -p, --path=@var{path}
|
||||||
|
Device/socket path (the default for virtio-serial is
|
||||||
|
@samp{/dev/virtio-ports/org.qemu.guest_agent.0},
|
||||||
|
the default for isa-serial is @samp{/dev/ttyS0})
|
||||||
|
|
||||||
|
@item -l, --logfile=@var{path}
|
||||||
|
Set log file path (default is stderr).
|
||||||
|
|
||||||
|
@item -f, --pidfile=@var{path}
|
||||||
|
Specify pid file (default is @samp{/var/run/qemu-ga.pid}).
|
||||||
|
|
||||||
|
@item -F, --fsfreeze-hook=@var{path}
|
||||||
|
Enable fsfreeze hook. Accepts an optional argument that specifies
|
||||||
|
script to run on freeze/thaw. Script will be called with
|
||||||
|
'freeze'/'thaw' arguments accordingly (default is
|
||||||
|
@samp{/etc/qemu/fsfreeze-hook}). If using -F with an argument, do
|
||||||
|
not follow -F with a space (for example:
|
||||||
|
@samp{-F/var/run/fsfreezehook.sh}).
|
||||||
|
|
||||||
|
@item -t, --statedir=@var{path}
|
||||||
|
Specify the directory to store state information (absolute paths only,
|
||||||
|
default is @samp{/var/run}).
|
||||||
|
|
||||||
|
@item -v, --verbose
|
||||||
|
Log extra debugging information.
|
||||||
|
|
||||||
|
@item -V, --version
|
||||||
|
Print version information and exit.
|
||||||
|
|
||||||
|
@item -d, --daemon
|
||||||
|
Daemonize after startup (detach from terminal).
|
||||||
|
|
||||||
|
@item -b, --blacklist=@var{list}
|
||||||
|
Comma-separated list of RPCs to disable (no spaces, @samp{?} to list
|
||||||
|
available RPCs).
|
||||||
|
|
||||||
|
@item -D, --dump-conf
|
||||||
|
Dump the configuration in a format compatible with @file{qemu-ga.conf}
|
||||||
|
and exit.
|
||||||
|
|
||||||
|
@item -h, --help
|
||||||
|
Display this help and exit.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@c man end
|
||||||
|
|
||||||
|
@c man begin FILES
|
||||||
|
|
||||||
|
The syntax of the @file{qemu-ga.conf} configuration file follows the
|
||||||
|
Desktop Entry Specification, here is a quick summary: it consists of
|
||||||
|
groups of key-value pairs, interspersed with comments.
|
||||||
|
|
||||||
|
@example
|
||||||
|
# qemu-ga configuration sample
|
||||||
|
[general]
|
||||||
|
daemonize = 0
|
||||||
|
pidfile = /var/run/qemu-ga.pid
|
||||||
|
verbose = 0
|
||||||
|
method = virtio-serial
|
||||||
|
path = /dev/virtio-ports/org.qemu.guest_agent.0
|
||||||
|
statedir = /var/run
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The list of keys follows the command line options:
|
||||||
|
@table @option
|
||||||
|
@item daemon= boolean
|
||||||
|
@item method= string
|
||||||
|
@item path= string
|
||||||
|
@item logfile= string
|
||||||
|
@item pidfile= string
|
||||||
|
@item fsfreeze-hook= string
|
||||||
|
@item statedir= string
|
||||||
|
@item verbose= boolean
|
||||||
|
@item blacklist= string list
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@c man end
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
|
||||||
|
@setfilename qemu-ga
|
||||||
|
@settitle QEMU Guest Agent
|
||||||
|
|
||||||
|
@c man begin AUTHOR
|
||||||
|
Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||||
|
@c man end
|
||||||
|
|
||||||
|
@c man begin SEEALSO
|
||||||
|
qemu(1)
|
||||||
|
@c man end
|
||||||
|
|
||||||
|
@end ignore
|
@ -2454,7 +2454,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
|||||||
char **p = (char **)list;
|
char **p = (char **)list;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
blacklist = g_list_append(blacklist, *p++);
|
blacklist = g_list_append(blacklist, g_strdup(*p++));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2468,13 +2468,13 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
|||||||
char **p = (char **)list;
|
char **p = (char **)list;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
blacklist = g_list_append(blacklist, *p++);
|
blacklist = g_list_append(blacklist, g_strdup(*p++));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(CONFIG_FSTRIM)
|
#if !defined(CONFIG_FSTRIM)
|
||||||
blacklist = g_list_append(blacklist, (char *)"guest-fstrim");
|
blacklist = g_list_append(blacklist, g_strdup("guest-fstrim"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return blacklist;
|
return blacklist;
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
#include <setupapi.h>
|
#include <setupapi.h>
|
||||||
#include <initguid.h>
|
#include <initguid.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <lm.h>
|
||||||
|
|
||||||
#include "qga/guest-agent-core.h"
|
#include "qga/guest-agent-core.h"
|
||||||
#include "qga/vss-win32.h"
|
#include "qga/vss-win32.h"
|
||||||
#include "qga-qmp-commands.h"
|
#include "qga-qmp-commands.h"
|
||||||
@ -1192,12 +1194,84 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
get_net_error_message(gint error)
|
||||||
|
{
|
||||||
|
HMODULE module = NULL;
|
||||||
|
gchar *retval = NULL;
|
||||||
|
wchar_t *msg = NULL;
|
||||||
|
int flags, nchars;
|
||||||
|
|
||||||
|
flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||||
|
|FORMAT_MESSAGE_IGNORE_INSERTS
|
||||||
|
|FORMAT_MESSAGE_FROM_SYSTEM;
|
||||||
|
|
||||||
|
if (error >= NERR_BASE && error <= MAX_NERR) {
|
||||||
|
module = LoadLibraryExW(L"netmsg.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
|
||||||
|
|
||||||
|
if (module != NULL) {
|
||||||
|
flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatMessageW(flags, module, error, 0, (LPWSTR)&msg, 0, NULL);
|
||||||
|
|
||||||
|
if (msg != NULL) {
|
||||||
|
nchars = wcslen(msg);
|
||||||
|
|
||||||
|
if (nchars > 2 && msg[nchars-1] == '\n' && msg[nchars-2] == '\r') {
|
||||||
|
msg[nchars-2] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = g_utf16_to_utf8(msg, -1, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
LocalFree(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module != NULL) {
|
||||||
|
FreeLibrary(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
void qmp_guest_set_user_password(const char *username,
|
void qmp_guest_set_user_password(const char *username,
|
||||||
const char *password,
|
const char *password,
|
||||||
bool crypted,
|
bool crypted,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
error_setg(errp, QERR_UNSUPPORTED);
|
NET_API_STATUS nas;
|
||||||
|
char *rawpasswddata = NULL;
|
||||||
|
size_t rawpasswdlen;
|
||||||
|
wchar_t *user, *wpass;
|
||||||
|
USER_INFO_1003 pi1003 = { 0, };
|
||||||
|
|
||||||
|
if (crypted) {
|
||||||
|
error_setg(errp, QERR_UNSUPPORTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawpasswddata = (char *)g_base64_decode(password, &rawpasswdlen);
|
||||||
|
rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
|
||||||
|
rawpasswddata[rawpasswdlen] = '\0';
|
||||||
|
|
||||||
|
user = g_utf8_to_utf16(username, -1, NULL, NULL, NULL);
|
||||||
|
wpass = g_utf8_to_utf16(rawpasswddata, -1, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
pi1003.usri1003_password = wpass;
|
||||||
|
nas = NetUserSetInfo(NULL, user,
|
||||||
|
1003, (LPBYTE)&pi1003,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (nas != NERR_Success) {
|
||||||
|
gchar *msg = get_net_error_message(nas);
|
||||||
|
error_setg(errp, "failed to set password: %s", msg);
|
||||||
|
g_free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(user);
|
||||||
|
g_free(wpass);
|
||||||
|
g_free(rawpasswddata);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
|
GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
|
||||||
@ -1225,7 +1299,6 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
|||||||
const char *list_unsupported[] = {
|
const char *list_unsupported[] = {
|
||||||
"guest-suspend-hybrid",
|
"guest-suspend-hybrid",
|
||||||
"guest-get-vcpus", "guest-set-vcpus",
|
"guest-get-vcpus", "guest-set-vcpus",
|
||||||
"guest-set-user-password",
|
|
||||||
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
||||||
"guest-get-memory-block-size",
|
"guest-get-memory-block-size",
|
||||||
"guest-fsfreeze-freeze-list",
|
"guest-fsfreeze-freeze-list",
|
||||||
@ -1233,7 +1306,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
|||||||
char **p = (char **)list_unsupported;
|
char **p = (char **)list_unsupported;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
blacklist = g_list_append(blacklist, *p++);
|
blacklist = g_list_append(blacklist, g_strdup(*p++));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vss_init(true)) {
|
if (!vss_init(true)) {
|
||||||
@ -1244,7 +1317,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
|||||||
p = (char **)list;
|
p = (char **)list;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
blacklist = g_list_append(blacklist, *p++);
|
blacklist = g_list_append(blacklist, g_strdup(*p++));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
<Product
|
<Product
|
||||||
Name="QEMU guest agent"
|
Name="QEMU guest agent"
|
||||||
Id="*"
|
Id="*"
|
||||||
UpgradeCode="{EB6B8302-C06E-4bec-ADAC-932C68A3A98D}"
|
UpgradeCode="{EB6B8302-C06E-4BEC-ADAC-932C68A3A98D}"
|
||||||
Manufacturer="$(env.QEMU_GA_MANUFACTURER)"
|
Manufacturer="$(env.QEMU_GA_MANUFACTURER)"
|
||||||
Version="$(env.QEMU_GA_VERSION)"
|
Version="$(env.QEMU_GA_VERSION)"
|
||||||
Language="1033">
|
Language="1033">
|
||||||
@ -58,29 +58,15 @@
|
|||||||
/>
|
/>
|
||||||
<Media Id="1" Cabinet="qemu_ga.$(env.QEMU_GA_VERSION).cab" EmbedCab="yes" />
|
<Media Id="1" Cabinet="qemu_ga.$(env.QEMU_GA_VERSION).cab" EmbedCab="yes" />
|
||||||
<Property Id="WHSLogo">1</Property>
|
<Property Id="WHSLogo">1</Property>
|
||||||
<Property Id="PREVIOUSVERSIONSINSTALLED" />
|
<MajorUpgrade
|
||||||
<Upgrade Id="{EB6B8302-C06E-4bec-ADAC-932C68A3A98D}">
|
DowngradeErrorMessage="Error: A newer version of QEMU guest agent is already installed."
|
||||||
<UpgradeVersion
|
/>
|
||||||
Minimum="1.0.0.0" Maximum="$(env.QEMU_GA_VERSION)"
|
|
||||||
Property="PREVIOUSVERSIONSINSTALLED"
|
|
||||||
IncludeMinimum="yes" IncludeMaximum="no" />
|
|
||||||
</Upgrade>
|
|
||||||
|
|
||||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||||
<Directory Id="$(var.GaProgramFilesFolder)" Name="QEMU Guest Agent">
|
<Directory Id="$(var.GaProgramFilesFolder)" Name="QEMU Guest Agent">
|
||||||
<Directory Id="qemu_ga_directory" Name="Qemu-ga">
|
<Directory Id="qemu_ga_directory" Name="Qemu-ga">
|
||||||
<Component Id="qemu_ga" Guid="{908B7199-DE2A-4dc6-A8D0-27A5AE444FEA}">
|
<Component Id="qemu_ga" Guid="{908B7199-DE2A-4DC6-A8D0-27A5AE444FEA}">
|
||||||
<File Id="qemu_ga.exe" Name="qemu-ga.exe" Source="../../qemu-ga.exe" KeyPath="yes" DiskId="1"/>
|
<File Id="qemu_ga.exe" Name="qemu-ga.exe" Source="$(env.BUILD_DIR)/qemu-ga.exe" KeyPath="yes" DiskId="1"/>
|
||||||
<?ifdef var.InstallVss ?>
|
|
||||||
<File Id="qga_vss.dll" Name="qga-vss.dll" Source="../vss-win32/qga-vss.dll" KeyPath="no" DiskId="1"/>
|
|
||||||
<File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="../vss-win32/qga-vss.tlb" KeyPath="no" DiskId="1"/>
|
|
||||||
<?endif?>
|
|
||||||
<File Id="iconv.dll" Name="iconv.dll" Source="$(var.Mingw_bin)/iconv.dll" KeyPath="no" DiskId="1"/>
|
|
||||||
<File Id="libgcc_arch_lib" Name="$(var.ArchLib)" Source="$(var.Mingw_bin)/$(var.ArchLib)" KeyPath="no" DiskId="1"/>
|
|
||||||
<File Id="libglib_2.0_0.dll" Name="libglib-2.0-0.dll" Source="$(var.Mingw_bin)/libglib-2.0-0.dll" KeyPath="no" DiskId="1"/>
|
|
||||||
<File Id="libintl_8.dll" Name="libintl-8.dll" Source="$(var.Mingw_bin)/libintl-8.dll" KeyPath="no" DiskId="1"/>
|
|
||||||
<File Id="libssp_0.dll" Name="libssp-0.dll" Source="$(var.Mingw_bin)/libssp-0.dll" KeyPath="no" DiskId="1"/>
|
|
||||||
<File Id="libwinpthread_1.dll" Name="libwinpthread-1.dll" Source="$(var.Mingw_bin)/libwinpthread-1.dll" KeyPath="no" DiskId="1"/>
|
|
||||||
<ServiceInstall
|
<ServiceInstall
|
||||||
Id="ServiceInstaller"
|
Id="ServiceInstaller"
|
||||||
Type="ownProcess"
|
Type="ownProcess"
|
||||||
@ -97,8 +83,33 @@
|
|||||||
</ServiceInstall>
|
</ServiceInstall>
|
||||||
<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="QEMU-GA" Wait="no" />
|
<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="QEMU-GA" Wait="no" />
|
||||||
</Component>
|
</Component>
|
||||||
|
<?ifdef var.InstallVss?>
|
||||||
<Component Id="registry_entries" Guid="d075d109-51ca-11e3-9f8b-000c29858960">
|
<Component Id="qga_vss_dll" Guid="{CB19C453-FABB-4BB1-ABAB-6B74F687BFBB}">
|
||||||
|
<File Id="qga_vss.dll" Name="qga-vss.dll" Source="$(env.BUILD_DIR)/qga/vss-win32/qga-vss.dll" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<Component Id="qga_vss_tlb" Guid="{D8D584B1-59C2-4FB7-A91F-636FF7BFA66E}">
|
||||||
|
<File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="$(env.BUILD_DIR)/qga/vss-win32/qga-vss.tlb" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<?endif?>
|
||||||
|
<Component Id="iconv" Guid="{35EE3558-D34B-4F0A-B8BD-430FF0775246}">
|
||||||
|
<File Id="iconv.dll" Name="iconv.dll" Source="$(var.Mingw_bin)/iconv.dll" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<Component Id="libgcc_arch_lib" Guid="{ADD4D07D-4515-4AB6-AF3E-C904961B4BB0}">
|
||||||
|
<File Id="libgcc_arch_lib" Name="$(var.ArchLib)" Source="$(var.Mingw_bin)/$(var.ArchLib)" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<Component Id="libglib" Guid="{D31BFD83-2773-4B65-B45A-E0D2ADA58679}">
|
||||||
|
<File Id="libglib_2.0_0.dll" Name="libglib-2.0-0.dll" Source="$(var.Mingw_bin)/libglib-2.0-0.dll" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<Component Id="libintl" Guid="{A641BC2D-A907-4A94-9149-F30ED430878F}">
|
||||||
|
<File Id="libintl_8.dll" Name="libintl-8.dll" Source="$(var.Mingw_bin)/libintl-8.dll" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<Component Id="libssp" Guid="{7880087B-02B4-4EF6-A5D3-D18F8E3D90E1}">
|
||||||
|
<File Id="libssp_0.dll" Name="libssp-0.dll" Source="$(var.Mingw_bin)/libssp-0.dll" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<Component Id="libwinpthread" Guid="{6C117C78-0F47-4B07-8F34-6BEE11643829}">
|
||||||
|
<File Id="libwinpthread_1.dll" Name="libwinpthread-1.dll" Source="$(var.Mingw_bin)/libwinpthread-1.dll" KeyPath="yes" DiskId="1"/>
|
||||||
|
</Component>
|
||||||
|
<Component Id="registry_entries" Guid="{D075D109-51CA-11E3-9F8B-000C29858960}">
|
||||||
<RegistryKey Root="HKLM"
|
<RegistryKey Root="HKLM"
|
||||||
Key="Software\$(env.QEMU_GA_MANUFACTURER)\$(env.QEMU_GA_DISTRO)\Tools\QemuGA">
|
Key="Software\$(env.QEMU_GA_MANUFACTURER)\$(env.QEMU_GA_DISTRO)\Tools\QemuGA">
|
||||||
<RegistryValue Type="string" Name="ProductID" Value="fb0a0d66-c7fb-4e2e-a16b-c4a3bfe8d13b" />
|
<RegistryValue Type="string" Name="ProductID" Value="fb0a0d66-c7fb-4e2e-a16b-c4a3bfe8d13b" />
|
||||||
@ -110,10 +121,11 @@
|
|||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<Property Id="cmd" Value="cmd.exe"/>
|
<Property Id="cmd" Value="cmd.exe"/>
|
||||||
|
<Property Id="REINSTALLMODE" Value="amus"/>
|
||||||
|
|
||||||
<?ifdef var.InstallVss ?>
|
<?ifdef var.InstallVss?>
|
||||||
<CustomAction Id="RegisterCom"
|
<CustomAction Id="RegisterCom"
|
||||||
ExeCommand='/c "[qemu_ga_directory]qemu-ga.exe" -s vss-install'
|
ExeCommand='/c "[qemu_ga_directory]qemu-ga.exe" -s vss-install'
|
||||||
Execute="deferred"
|
Execute="deferred"
|
||||||
Property="cmd"
|
Property="cmd"
|
||||||
Impersonate="no"
|
Impersonate="no"
|
||||||
@ -126,19 +138,29 @@
|
|||||||
Property="cmd"
|
Property="cmd"
|
||||||
Impersonate="no"
|
Impersonate="no"
|
||||||
Return="check"
|
Return="check"
|
||||||
></CustomAction>
|
>
|
||||||
|
</CustomAction>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<Feature Id="QEMUFeature" Title="QEMU Guest Agent" Level="1">
|
<Feature Id="QEMUFeature" Title="QEMU Guest Agent" Level="1">
|
||||||
<ComponentRef Id="qemu_ga" />
|
<ComponentRef Id="qemu_ga" />
|
||||||
|
<?ifdef var.InstallVss?>
|
||||||
|
<ComponentRef Id="qga_vss_dll" />
|
||||||
|
<ComponentRef Id="qga_vss_tlb" />
|
||||||
|
<?endif?>
|
||||||
|
<ComponentRef Id="iconv" />
|
||||||
|
<ComponentRef Id="libgcc_arch_lib" />
|
||||||
|
<ComponentRef Id="libglib" />
|
||||||
|
<ComponentRef Id="libintl" />
|
||||||
|
<ComponentRef Id="libssp" />
|
||||||
|
<ComponentRef Id="libwinpthread" />
|
||||||
<ComponentRef Id="registry_entries" />
|
<ComponentRef Id="registry_entries" />
|
||||||
</Feature>
|
</Feature>
|
||||||
|
|
||||||
<InstallExecuteSequence>
|
<InstallExecuteSequence>
|
||||||
<RemoveExistingProducts Before="InstallInitialize" />
|
<?ifdef var.InstallVss?>
|
||||||
<?ifdef var.InstallVss ?>
|
|
||||||
<Custom Action="RegisterCom" After="InstallServices">NOT Installed</Custom>
|
|
||||||
<Custom Action="UnRegisterCom" After="StopServices">Installed</Custom>
|
<Custom Action="UnRegisterCom" After="StopServices">Installed</Custom>
|
||||||
|
<Custom Action="RegisterCom" After="InstallServices">NOT REMOVE</Custom>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
</InstallExecuteSequence>
|
</InstallExecuteSequence>
|
||||||
</Product>
|
</Product>
|
||||||
|
479
qga/main.c
479
qga/main.c
@ -56,6 +56,7 @@
|
|||||||
#define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook"
|
#define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook"
|
||||||
#endif
|
#endif
|
||||||
#define QGA_SENTINEL_BYTE 0xFF
|
#define QGA_SENTINEL_BYTE 0xFF
|
||||||
|
#define QGA_CONF_DEFAULT CONFIG_QEMU_CONFDIR G_DIR_SEPARATOR_S "qemu-ga.conf"
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
const char *state_dir;
|
const char *state_dir;
|
||||||
@ -82,7 +83,7 @@ struct GAState {
|
|||||||
bool delimit_response;
|
bool delimit_response;
|
||||||
bool frozen;
|
bool frozen;
|
||||||
GList *blacklist;
|
GList *blacklist;
|
||||||
const char *state_filepath_isfrozen;
|
char *state_filepath_isfrozen;
|
||||||
struct {
|
struct {
|
||||||
const char *log_filepath;
|
const char *log_filepath;
|
||||||
const char *pid_filepath;
|
const char *pid_filepath;
|
||||||
@ -90,7 +91,7 @@ struct GAState {
|
|||||||
#ifdef CONFIG_FSFREEZE
|
#ifdef CONFIG_FSFREEZE
|
||||||
const char *fsfreeze_hook;
|
const char *fsfreeze_hook;
|
||||||
#endif
|
#endif
|
||||||
const gchar *pstate_filepath;
|
gchar *pstate_filepath;
|
||||||
GAPersistentState pstate;
|
GAPersistentState pstate;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -215,6 +216,8 @@ static void usage(const char *cmd)
|
|||||||
#endif
|
#endif
|
||||||
" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\"\n"
|
" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\"\n"
|
||||||
" to list available RPCs)\n"
|
" to list available RPCs)\n"
|
||||||
|
" -D, --dump-conf dump a qemu-ga config file based on current config\n"
|
||||||
|
" options / command-line parameters to stdout\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Report bugs to <mdroth@linux.vnet.ibm.com>\n"
|
"Report bugs to <mdroth@linux.vnet.ibm.com>\n"
|
||||||
@ -658,23 +661,6 @@ static gboolean channel_init(GAState *s, const gchar *method, const gchar *path)
|
|||||||
{
|
{
|
||||||
GAChannelMethod channel_method;
|
GAChannelMethod channel_method;
|
||||||
|
|
||||||
if (method == NULL) {
|
|
||||||
method = "virtio-serial";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path == NULL) {
|
|
||||||
if (strcmp(method, "virtio-serial") == 0 ) {
|
|
||||||
/* try the default path for the virtio-serial port */
|
|
||||||
path = QGA_VIRTIO_PATH_DEFAULT;
|
|
||||||
} else if (strcmp(method, "isa-serial") == 0){
|
|
||||||
/* try the default path for the serial port - COM1 */
|
|
||||||
path = QGA_SERIAL_PATH_DEFAULT;
|
|
||||||
} else {
|
|
||||||
g_critical("must specify a path for this channel");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(method, "virtio-serial") == 0) {
|
if (strcmp(method, "virtio-serial") == 0) {
|
||||||
s->virtio = true; /* virtio requires special handling in some cases */
|
s->virtio = true; /* virtio requires special handling in some cases */
|
||||||
channel_method = GA_CHANNEL_VIRTIO_SERIAL;
|
channel_method = GA_CHANNEL_VIRTIO_SERIAL;
|
||||||
@ -921,22 +907,164 @@ static void ga_print_cmd(QmpCommand *cmd, void *opaque)
|
|||||||
printf("%s\n", qmp_command_name(cmd));
|
printf("%s\n", qmp_command_name(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
static GList *split_list(const gchar *str, const gchar *delim)
|
||||||
{
|
{
|
||||||
const char *sopt = "hVvdm:p:l:f:F::b:s:t:";
|
GList *list = NULL;
|
||||||
const char *method = NULL, *path = NULL;
|
int i;
|
||||||
const char *log_filepath = NULL;
|
gchar **strv;
|
||||||
const char *pid_filepath;
|
|
||||||
|
strv = g_strsplit(str, delim, -1);
|
||||||
|
for (i = 0; strv[i]; i++) {
|
||||||
|
list = g_list_prepend(list, strv[i]);
|
||||||
|
}
|
||||||
|
g_free(strv);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct GAConfig {
|
||||||
|
char *channel_path;
|
||||||
|
char *method;
|
||||||
|
char *log_filepath;
|
||||||
|
char *pid_filepath;
|
||||||
#ifdef CONFIG_FSFREEZE
|
#ifdef CONFIG_FSFREEZE
|
||||||
const char *fsfreeze_hook = NULL;
|
char *fsfreeze_hook;
|
||||||
#endif
|
#endif
|
||||||
const char *state_dir;
|
char *state_dir;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const char *service = NULL;
|
const char *service;
|
||||||
#endif
|
#endif
|
||||||
|
gchar *bliststr; /* blacklist may point to this string */
|
||||||
|
GList *blacklist;
|
||||||
|
int daemonize;
|
||||||
|
GLogLevelFlags log_level;
|
||||||
|
int dumpconf;
|
||||||
|
} GAConfig;
|
||||||
|
|
||||||
|
static void config_load(GAConfig *config)
|
||||||
|
{
|
||||||
|
GError *gerr = NULL;
|
||||||
|
GKeyFile *keyfile;
|
||||||
|
|
||||||
|
/* read system config */
|
||||||
|
keyfile = g_key_file_new();
|
||||||
|
if (!g_key_file_load_from_file(keyfile, QGA_CONF_DEFAULT, 0, &gerr)) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "daemon", NULL)) {
|
||||||
|
config->daemonize =
|
||||||
|
g_key_file_get_boolean(keyfile, "general", "daemon", &gerr);
|
||||||
|
}
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "method", NULL)) {
|
||||||
|
config->method =
|
||||||
|
g_key_file_get_string(keyfile, "general", "method", &gerr);
|
||||||
|
}
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "path", NULL)) {
|
||||||
|
config->channel_path =
|
||||||
|
g_key_file_get_string(keyfile, "general", "path", &gerr);
|
||||||
|
}
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "logfile", NULL)) {
|
||||||
|
config->log_filepath =
|
||||||
|
g_key_file_get_string(keyfile, "general", "logfile", &gerr);
|
||||||
|
}
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "pidfile", NULL)) {
|
||||||
|
config->pid_filepath =
|
||||||
|
g_key_file_get_string(keyfile, "general", "pidfile", &gerr);
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_FSFREEZE
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "fsfreeze-hook", NULL)) {
|
||||||
|
config->fsfreeze_hook =
|
||||||
|
g_key_file_get_string(keyfile,
|
||||||
|
"general", "fsfreeze-hook", &gerr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "statedir", NULL)) {
|
||||||
|
config->state_dir =
|
||||||
|
g_key_file_get_string(keyfile, "general", "statedir", &gerr);
|
||||||
|
}
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "verbose", NULL) &&
|
||||||
|
g_key_file_get_boolean(keyfile, "general", "verbose", &gerr)) {
|
||||||
|
/* enable all log levels */
|
||||||
|
config->log_level = G_LOG_LEVEL_MASK;
|
||||||
|
}
|
||||||
|
if (g_key_file_has_key(keyfile, "general", "blacklist", NULL)) {
|
||||||
|
config->bliststr =
|
||||||
|
g_key_file_get_string(keyfile, "general", "blacklist", &gerr);
|
||||||
|
config->blacklist = g_list_concat(config->blacklist,
|
||||||
|
split_list(config->bliststr, ","));
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
g_key_file_free(keyfile);
|
||||||
|
if (gerr &&
|
||||||
|
!(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT)) {
|
||||||
|
g_critical("error loading configuration from path: %s, %s",
|
||||||
|
QGA_CONF_DEFAULT, gerr->message);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
g_clear_error(&gerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar *list_join(GList *list, const gchar separator)
|
||||||
|
{
|
||||||
|
GString *str = g_string_new("");
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
str = g_string_append(str, (gchar *)list->data);
|
||||||
|
list = g_list_next(list);
|
||||||
|
if (list) {
|
||||||
|
str = g_string_append_c(str, separator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_string_free(str, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_dump(GAConfig *config)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
GKeyFile *keyfile;
|
||||||
|
gchar *tmp;
|
||||||
|
|
||||||
|
keyfile = g_key_file_new();
|
||||||
|
g_assert(keyfile);
|
||||||
|
|
||||||
|
g_key_file_set_boolean(keyfile, "general", "daemon", config->daemonize);
|
||||||
|
g_key_file_set_string(keyfile, "general", "method", config->method);
|
||||||
|
g_key_file_set_string(keyfile, "general", "path", config->channel_path);
|
||||||
|
if (config->log_filepath) {
|
||||||
|
g_key_file_set_string(keyfile, "general", "logfile",
|
||||||
|
config->log_filepath);
|
||||||
|
}
|
||||||
|
g_key_file_set_string(keyfile, "general", "pidfile", config->pid_filepath);
|
||||||
|
#ifdef CONFIG_FSFREEZE
|
||||||
|
if (config->fsfreeze_hook) {
|
||||||
|
g_key_file_set_string(keyfile, "general", "fsfreeze-hook",
|
||||||
|
config->fsfreeze_hook);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
g_key_file_set_string(keyfile, "general", "statedir", config->state_dir);
|
||||||
|
g_key_file_set_boolean(keyfile, "general", "verbose",
|
||||||
|
config->log_level == G_LOG_LEVEL_MASK);
|
||||||
|
tmp = list_join(config->blacklist, ',');
|
||||||
|
g_key_file_set_string(keyfile, "general", "blacklist", tmp);
|
||||||
|
g_free(tmp);
|
||||||
|
|
||||||
|
tmp = g_key_file_to_data(keyfile, NULL, &error);
|
||||||
|
printf("%s", tmp);
|
||||||
|
|
||||||
|
g_free(tmp);
|
||||||
|
g_key_file_free(keyfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_parse(GAConfig *config, int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *sopt = "hVvdm:p:l:f:F::b:s:t:D";
|
||||||
|
int opt_ind = 0, ch;
|
||||||
const struct option lopt[] = {
|
const struct option lopt[] = {
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ "version", 0, NULL, 'V' },
|
{ "version", 0, NULL, 'V' },
|
||||||
|
{ "dump-conf", 0, NULL, 'D' },
|
||||||
{ "logfile", 1, NULL, 'l' },
|
{ "logfile", 1, NULL, 'l' },
|
||||||
{ "pidfile", 1, NULL, 'f' },
|
{ "pidfile", 1, NULL, 'f' },
|
||||||
#ifdef CONFIG_FSFREEZE
|
#ifdef CONFIG_FSFREEZE
|
||||||
@ -953,141 +1081,115 @@ int main(int argc, char **argv)
|
|||||||
{ "statedir", 1, NULL, 't' },
|
{ "statedir", 1, NULL, 't' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
int opt_ind = 0, ch, daemonize = 0, i, j, len;
|
|
||||||
GLogLevelFlags log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
|
|
||||||
GList *blacklist = NULL;
|
|
||||||
GAState *s;
|
|
||||||
|
|
||||||
module_call_init(MODULE_INIT_QAPI);
|
config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
|
||||||
|
|
||||||
init_dfl_pathnames();
|
|
||||||
pid_filepath = dfl_pathnames.pidfile;
|
|
||||||
state_dir = dfl_pathnames.state_dir;
|
|
||||||
|
|
||||||
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'm':
|
case 'm':
|
||||||
method = optarg;
|
g_free(config->method);
|
||||||
|
config->method = g_strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
path = optarg;
|
g_free(config->channel_path);
|
||||||
|
config->channel_path = g_strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
log_filepath = optarg;
|
g_free(config->log_filepath);
|
||||||
|
config->log_filepath = g_strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
pid_filepath = optarg;
|
g_free(config->pid_filepath);
|
||||||
|
config->pid_filepath = g_strdup(optarg);
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_FSFREEZE
|
#ifdef CONFIG_FSFREEZE
|
||||||
case 'F':
|
case 'F':
|
||||||
fsfreeze_hook = optarg ? optarg : QGA_FSFREEZE_HOOK_DEFAULT;
|
g_free(config->fsfreeze_hook);
|
||||||
|
config->fsfreeze_hook = g_strdup(optarg ?: QGA_FSFREEZE_HOOK_DEFAULT);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 't':
|
case 't':
|
||||||
state_dir = optarg;
|
g_free(config->state_dir);
|
||||||
break;
|
config->state_dir = g_strdup(optarg);
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
/* enable all log levels */
|
/* enable all log levels */
|
||||||
log_level = G_LOG_LEVEL_MASK;
|
config->log_level = G_LOG_LEVEL_MASK;
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("QEMU Guest Agent %s\n", QEMU_VERSION);
|
printf("QEMU Guest Agent %s\n", QEMU_VERSION);
|
||||||
return 0;
|
exit(EXIT_SUCCESS);
|
||||||
case 'd':
|
case 'd':
|
||||||
daemonize = 1;
|
config->daemonize = 1;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
config->dumpconf = 1;
|
||||||
break;
|
break;
|
||||||
case 'b': {
|
case 'b': {
|
||||||
if (is_help_option(optarg)) {
|
if (is_help_option(optarg)) {
|
||||||
qmp_for_each_command(ga_print_cmd, NULL);
|
qmp_for_each_command(ga_print_cmd, NULL);
|
||||||
return 0;
|
exit(EXIT_SUCCESS);
|
||||||
}
|
|
||||||
for (j = 0, i = 0, len = strlen(optarg); i < len; i++) {
|
|
||||||
if (optarg[i] == ',') {
|
|
||||||
optarg[i] = 0;
|
|
||||||
blacklist = g_list_append(blacklist, &optarg[j]);
|
|
||||||
j = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j < i) {
|
|
||||||
blacklist = g_list_append(blacklist, &optarg[j]);
|
|
||||||
}
|
}
|
||||||
|
config->blacklist = g_list_concat(config->blacklist,
|
||||||
|
split_list(optarg, ","));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
case 's':
|
case 's':
|
||||||
service = optarg;
|
config->service = optarg;
|
||||||
if (strcmp(service, "install") == 0) {
|
if (strcmp(config->service, "install") == 0) {
|
||||||
const char *fixed_state_dir;
|
|
||||||
|
|
||||||
/* If the user passed the "-t" option, we save that state dir
|
|
||||||
* in the service. Otherwise we let the service fetch the state
|
|
||||||
* dir from the environment when it starts.
|
|
||||||
*/
|
|
||||||
fixed_state_dir = (state_dir == dfl_pathnames.state_dir) ?
|
|
||||||
NULL :
|
|
||||||
state_dir;
|
|
||||||
if (ga_install_vss_provider()) {
|
if (ga_install_vss_provider()) {
|
||||||
return EXIT_FAILURE;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (ga_install_service(path, log_filepath, fixed_state_dir)) {
|
if (ga_install_service(config->channel_path,
|
||||||
return EXIT_FAILURE;
|
config->log_filepath, config->state_dir)) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
return 0;
|
exit(EXIT_SUCCESS);
|
||||||
} else if (strcmp(service, "uninstall") == 0) {
|
} else if (strcmp(config->service, "uninstall") == 0) {
|
||||||
ga_uninstall_vss_provider();
|
ga_uninstall_vss_provider();
|
||||||
return ga_uninstall_service();
|
exit(ga_uninstall_service());
|
||||||
} else if (strcmp(service, "vss-install") == 0) {
|
} else if (strcmp(config->service, "vss-install") == 0) {
|
||||||
if (ga_install_vss_provider()) {
|
if (ga_install_vss_provider()) {
|
||||||
return EXIT_FAILURE;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
exit(EXIT_SUCCESS);
|
||||||
} else if (strcmp(service, "vss-uninstall") == 0) {
|
} else if (strcmp(config->service, "vss-uninstall") == 0) {
|
||||||
ga_uninstall_vss_provider();
|
ga_uninstall_vss_provider();
|
||||||
return EXIT_SUCCESS;
|
exit(EXIT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
printf("Unknown service command.\n");
|
printf("Unknown service command.\n");
|
||||||
return EXIT_FAILURE;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 0;
|
exit(EXIT_SUCCESS);
|
||||||
case '?':
|
case '?':
|
||||||
g_print("Unknown option, try '%s --help' for more information.\n",
|
g_print("Unknown option, try '%s --help' for more information.\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
return EXIT_FAILURE;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
static void config_free(GAConfig *config)
|
||||||
/* On win32 the state directory is application specific (be it the default
|
{
|
||||||
* or a user override). We got past the command line parsing; let's create
|
g_free(config->method);
|
||||||
* the directory (with any intermediate directories). If we run into an
|
g_free(config->log_filepath);
|
||||||
* error later on, we won't try to clean up the directory, it is considered
|
g_free(config->pid_filepath);
|
||||||
* persistent.
|
g_free(config->state_dir);
|
||||||
*/
|
g_free(config->channel_path);
|
||||||
if (g_mkdir_with_parents(state_dir, S_IRWXU) == -1) {
|
g_free(config->bliststr);
|
||||||
g_critical("unable to create (an ancestor of) the state directory"
|
|
||||||
" '%s': %s", state_dir, strerror(errno));
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s = g_malloc0(sizeof(GAState));
|
|
||||||
s->log_level = log_level;
|
|
||||||
s->log_file = stderr;
|
|
||||||
#ifdef CONFIG_FSFREEZE
|
#ifdef CONFIG_FSFREEZE
|
||||||
s->fsfreeze_hook = fsfreeze_hook;
|
g_free(config->fsfreeze_hook);
|
||||||
#endif
|
#endif
|
||||||
g_log_set_default_handler(ga_log, s);
|
g_free(config);
|
||||||
g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR);
|
}
|
||||||
ga_enable_logging(s);
|
|
||||||
s->state_filepath_isfrozen = g_strdup_printf("%s/qga.state.isfrozen",
|
|
||||||
state_dir);
|
|
||||||
s->pstate_filepath = g_strdup_printf("%s/qga.state", state_dir);
|
|
||||||
s->frozen = false;
|
|
||||||
|
|
||||||
|
static bool check_is_frozen(GAState *s)
|
||||||
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
/* check if a previous instance of qemu-ga exited with filesystems' state
|
/* check if a previous instance of qemu-ga exited with filesystems' state
|
||||||
* marked as frozen. this could be a stale value (a non-qemu-ga process
|
* marked as frozen. this could be a stale value (a non-qemu-ga process
|
||||||
@ -1113,32 +1215,56 @@ int main(int argc, char **argv)
|
|||||||
" guest-fsfreeze-thaw is issued, or filesystems are"
|
" guest-fsfreeze-thaw is issued, or filesystems are"
|
||||||
" manually unfrozen and the file %s is removed",
|
" manually unfrozen and the file %s is removed",
|
||||||
s->state_filepath_isfrozen);
|
s->state_filepath_isfrozen);
|
||||||
s->frozen = true;
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int run_agent(GAState *s, GAConfig *config)
|
||||||
|
{
|
||||||
|
ga_state = s;
|
||||||
|
|
||||||
|
g_log_set_default_handler(ga_log, s);
|
||||||
|
g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR);
|
||||||
|
ga_enable_logging(s);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* On win32 the state directory is application specific (be it the default
|
||||||
|
* or a user override). We got past the command line parsing; let's create
|
||||||
|
* the directory (with any intermediate directories). If we run into an
|
||||||
|
* error later on, we won't try to clean up the directory, it is considered
|
||||||
|
* persistent.
|
||||||
|
*/
|
||||||
|
if (g_mkdir_with_parents(config->state_dir, S_IRWXU) == -1) {
|
||||||
|
g_critical("unable to create (an ancestor of) the state directory"
|
||||||
|
" '%s': %s", config->state_dir, strerror(errno));
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ga_is_frozen(s)) {
|
if (ga_is_frozen(s)) {
|
||||||
if (daemonize) {
|
if (config->daemonize) {
|
||||||
/* delay opening/locking of pidfile till filesystems are unfrozen */
|
/* delay opening/locking of pidfile till filesystems are unfrozen */
|
||||||
s->deferred_options.pid_filepath = pid_filepath;
|
s->deferred_options.pid_filepath = config->pid_filepath;
|
||||||
become_daemon(NULL);
|
become_daemon(NULL);
|
||||||
}
|
}
|
||||||
if (log_filepath) {
|
if (config->log_filepath) {
|
||||||
/* delay opening the log file till filesystems are unfrozen */
|
/* delay opening the log file till filesystems are unfrozen */
|
||||||
s->deferred_options.log_filepath = log_filepath;
|
s->deferred_options.log_filepath = config->log_filepath;
|
||||||
}
|
}
|
||||||
ga_disable_logging(s);
|
ga_disable_logging(s);
|
||||||
qmp_for_each_command(ga_disable_non_whitelisted, NULL);
|
qmp_for_each_command(ga_disable_non_whitelisted, NULL);
|
||||||
} else {
|
} else {
|
||||||
if (daemonize) {
|
if (config->daemonize) {
|
||||||
become_daemon(pid_filepath);
|
become_daemon(config->pid_filepath);
|
||||||
}
|
}
|
||||||
if (log_filepath) {
|
if (config->log_filepath) {
|
||||||
FILE *log_file = ga_open_logfile(log_filepath);
|
FILE *log_file = ga_open_logfile(config->log_filepath);
|
||||||
if (!log_file) {
|
if (!log_file) {
|
||||||
g_critical("unable to open specified log file: %s",
|
g_critical("unable to open specified log file: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
goto out_bad;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
s->log_file = log_file;
|
s->log_file = log_file;
|
||||||
}
|
}
|
||||||
@ -1149,17 +1275,18 @@ int main(int argc, char **argv)
|
|||||||
s->pstate_filepath,
|
s->pstate_filepath,
|
||||||
ga_is_frozen(s))) {
|
ga_is_frozen(s))) {
|
||||||
g_critical("failed to load persistent state");
|
g_critical("failed to load persistent state");
|
||||||
goto out_bad;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
blacklist = ga_command_blacklist_init(blacklist);
|
config->blacklist = ga_command_blacklist_init(config->blacklist);
|
||||||
if (blacklist) {
|
if (config->blacklist) {
|
||||||
s->blacklist = blacklist;
|
GList *l = config->blacklist;
|
||||||
|
s->blacklist = config->blacklist;
|
||||||
do {
|
do {
|
||||||
g_debug("disabling command: %s", (char *)blacklist->data);
|
g_debug("disabling command: %s", (char *)l->data);
|
||||||
qmp_disable_command(blacklist->data);
|
qmp_disable_command(l->data);
|
||||||
blacklist = g_list_next(blacklist);
|
l = g_list_next(l);
|
||||||
} while (blacklist);
|
} while (l);
|
||||||
}
|
}
|
||||||
s->command_state = ga_command_state_new();
|
s->command_state = ga_command_state_new();
|
||||||
ga_command_state_init(s, s->command_state);
|
ga_command_state_init(s, s->command_state);
|
||||||
@ -1169,19 +1296,19 @@ int main(int argc, char **argv)
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if (!register_signal_handlers()) {
|
if (!register_signal_handlers()) {
|
||||||
g_critical("failed to register signal handlers");
|
g_critical("failed to register signal handlers");
|
||||||
goto out_bad;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s->main_loop = g_main_loop_new(NULL, false);
|
s->main_loop = g_main_loop_new(NULL, false);
|
||||||
if (!channel_init(ga_state, method, path)) {
|
if (!channel_init(ga_state, config->method, config->channel_path)) {
|
||||||
g_critical("failed to initialize guest agent channel");
|
g_critical("failed to initialize guest agent channel");
|
||||||
goto out_bad;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
g_main_loop_run(ga_state->main_loop);
|
g_main_loop_run(ga_state->main_loop);
|
||||||
#else
|
#else
|
||||||
if (daemonize) {
|
if (config->daemonize) {
|
||||||
SERVICE_TABLE_ENTRY service_table[] = {
|
SERVICE_TABLE_ENTRY service_table[] = {
|
||||||
{ (char *)QGA_SERVICE_NAME, service_main }, { NULL, NULL } };
|
{ (char *)QGA_SERVICE_NAME, service_main }, { NULL, NULL } };
|
||||||
StartServiceCtrlDispatcher(service_table);
|
StartServiceCtrlDispatcher(service_table);
|
||||||
@ -1190,17 +1317,85 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ga_command_state_cleanup_all(ga_state->command_state);
|
return EXIT_SUCCESS;
|
||||||
ga_channel_free(ga_state->channel);
|
}
|
||||||
|
|
||||||
if (daemonize) {
|
static void free_blacklist_entry(gpointer entry, gpointer unused)
|
||||||
unlink(pid_filepath);
|
{
|
||||||
}
|
g_free(entry);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
out_bad:
|
int main(int argc, char **argv)
|
||||||
if (daemonize) {
|
{
|
||||||
unlink(pid_filepath);
|
int ret = EXIT_SUCCESS;
|
||||||
}
|
GAState *s = g_new0(GAState, 1);
|
||||||
return EXIT_FAILURE;
|
GAConfig *config = g_new0(GAConfig, 1);
|
||||||
|
|
||||||
|
module_call_init(MODULE_INIT_QAPI);
|
||||||
|
|
||||||
|
init_dfl_pathnames();
|
||||||
|
config_load(config);
|
||||||
|
config_parse(config, argc, argv);
|
||||||
|
|
||||||
|
if (config->pid_filepath == NULL) {
|
||||||
|
config->pid_filepath = g_strdup(dfl_pathnames.pidfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->state_dir == NULL) {
|
||||||
|
config->state_dir = g_strdup(dfl_pathnames.state_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->method == NULL) {
|
||||||
|
config->method = g_strdup("virtio-serial");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->channel_path == NULL) {
|
||||||
|
if (strcmp(config->method, "virtio-serial") == 0) {
|
||||||
|
/* try the default path for the virtio-serial port */
|
||||||
|
config->channel_path = g_strdup(QGA_VIRTIO_PATH_DEFAULT);
|
||||||
|
} else if (strcmp(config->method, "isa-serial") == 0) {
|
||||||
|
/* try the default path for the serial port - COM1 */
|
||||||
|
config->channel_path = g_strdup(QGA_SERIAL_PATH_DEFAULT);
|
||||||
|
} else {
|
||||||
|
g_critical("must specify a path for this channel");
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->log_level = config->log_level;
|
||||||
|
s->log_file = stderr;
|
||||||
|
#ifdef CONFIG_FSFREEZE
|
||||||
|
s->fsfreeze_hook = config->fsfreeze_hook;
|
||||||
|
#endif
|
||||||
|
s->pstate_filepath = g_strdup_printf("%s/qga.state", config->state_dir);
|
||||||
|
s->state_filepath_isfrozen = g_strdup_printf("%s/qga.state.isfrozen",
|
||||||
|
config->state_dir);
|
||||||
|
s->frozen = check_is_frozen(s);
|
||||||
|
|
||||||
|
if (config->dumpconf) {
|
||||||
|
config_dump(config);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = run_agent(s, config);
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (s->command_state) {
|
||||||
|
ga_command_state_cleanup_all(s->command_state);
|
||||||
|
}
|
||||||
|
if (s->channel) {
|
||||||
|
ga_channel_free(s->channel);
|
||||||
|
}
|
||||||
|
g_list_foreach(config->blacklist, free_blacklist_entry, NULL);
|
||||||
|
g_free(s->pstate_filepath);
|
||||||
|
g_free(s->state_filepath_isfrozen);
|
||||||
|
|
||||||
|
if (config->daemonize) {
|
||||||
|
unlink(config->pid_filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
config_free(config);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -793,7 +793,7 @@
|
|||||||
# scheme. Refer to the documentation of the guest operating system
|
# scheme. Refer to the documentation of the guest operating system
|
||||||
# in question to determine what is supported.
|
# in question to determine what is supported.
|
||||||
#
|
#
|
||||||
# Note all guest operating systems will support use of the
|
# Not all guest operating systems will support use of the
|
||||||
# @crypted flag, as they may require the clear-text password
|
# @crypted flag, as they may require the clear-text password
|
||||||
#
|
#
|
||||||
# The @password parameter must always be base64 encoded before
|
# The @password parameter must always be base64 encoded before
|
||||||
|
Loading…
Reference in New Issue
Block a user