aboutsummaryrefslogtreecommitdiff
path: root/emulators
diff options
context:
space:
mode:
authorNeel Chauhan <nc@FreeBSD.org>2021-03-16 23:30:47 +0000
committerNeel Chauhan <nc@FreeBSD.org>2021-03-16 23:30:47 +0000
commitc47779eeeac73dcfcb52402d4a12e455695ccd4d (patch)
treea5a58d362b7b03ff07ade48b0d0f7b41b9f677f1 /emulators
parenta0bd4fb1fab61c43a874b7dede2fa6784d4cfd6f (diff)
downloadports-c47779eeeac73dcfcb52402d4a12e455695ccd4d.tar.gz
ports-c47779eeeac73dcfcb52402d4a12e455695ccd4d.zip
New port: emulators/qemu-guest-agent: QEMU Guest Agent for FreeBSD
PR: 254105 Submitted by: zhecka AT gmail DOT com
Notes
Notes: svn path=/head/; revision=568621
Diffstat (limited to 'emulators')
-rw-r--r--emulators/Makefile1
-rw-r--r--emulators/qemu-guest-agent/Makefile183
-rw-r--r--emulators/qemu-guest-agent/distinfo7
-rw-r--r--emulators/qemu-guest-agent/files/patch-Makefile106
-rw-r--r--emulators/qemu-guest-agent/files/patch-configure201
-rw-r--r--emulators/qemu-guest-agent/files/patch-qga_commands-posix.c758
-rw-r--r--emulators/qemu-guest-agent/files/patch-qga_main.c30
-rw-r--r--emulators/qemu-guest-agent/files/qemu-guest-agent.in31
-rw-r--r--emulators/qemu-guest-agent/pkg-descr5
-rw-r--r--emulators/qemu-guest-agent/pkg-message17
-rw-r--r--emulators/qemu-guest-agent/pkg-message-1124
-rw-r--r--emulators/qemu-guest-agent/pkg-plist1
12 files changed, 1364 insertions, 0 deletions
diff --git a/emulators/Makefile b/emulators/Makefile
index 6f4c7eb999a4..c04b2617accb 100644
--- a/emulators/Makefile
+++ b/emulators/Makefile
@@ -113,6 +113,7 @@
SUBDIR += qemu
SUBDIR += qemu-cheri
SUBDIR += qemu-devel
+ SUBDIR += qemu-guest-agent
SUBDIR += qemu-powernv
SUBDIR += qemu-user-static
SUBDIR += qemu-user-static-devel
diff --git a/emulators/qemu-guest-agent/Makefile b/emulators/qemu-guest-agent/Makefile
new file mode 100644
index 000000000000..3fead1ff23ef
--- /dev/null
+++ b/emulators/qemu-guest-agent/Makefile
@@ -0,0 +1,183 @@
+# Created by: Kaltashkin Eugene <zhecka@gmail.com>
+# $FreeBSD$
+
+PORTNAME= qemu
+DISTVERSION= 5.0.1
+CATEGORIES= emulators
+MASTER_SITES= https://download.qemu.org/
+PKGNAMESUFFIX= -guest-agent
+
+MAINTAINER= zhecka@gmail.com
+COMMENT= QEMU guest-agent utilities
+
+LICENSE= GPLv2
+
+DIST_SUBDIR= qemu/${PORTVERSION}
+FILESDIR= ${.CURDIR}/files
+HAS_CONFIGURE= yes
+USES= gmake gnome pkgconfig python:build tar:xz
+USE_GNOME= glib20
+USE_RC_SUBR= qemu-guest-agent
+MAKE_ENV+= BSD_MAKE="${MAKE}" PREFIX=${PREFIX}
+
+CONFLICTS_INSTALL= qemu-[0-9]* qemu-devel-* qemu-sbruno-*
+OPTIONS_EXCLUDE=SAMBA X11 GTK3 OPENGL GNUTLS SASL JPEG PNG CURL \
+ CDROM_DMA PCAP USBREDIR GNS3 X86_TARGETS DOCS\
+ STATIC_LINK NCURSES VDE
+
+PLIST= ${.CURDIR}/pkg-plist
+DESCR= ${.CURDIR}/pkg-descr
+
+CONFIGURE_ARGS?=--localstatedir=/var --extra-ldflags=-L\"${LOCALBASE}/lib\" \
+ --mandir=${MANPREFIX}/man \
+ --prefix=${PREFIX} --cc=${CC} --disable-kvm \
+ --python=${PYTHON_CMD} \
+ --extra-cflags=-I${WRKSRC}\ -I${LOCALBASE}/include\ -DPREFIX=\\\"\"${PREFIX}\\\"\"\ -DBSD_GUEST_AGENT\ -DFREEBSD \
+ --disable-blobs \
+ --disable-system \
+ --disable-user \
+ --disable-linux-user \
+ --disable-bsd-user \
+ --disable-docs \
+ --enable-guest-agent \
+ --disable-guest-agent-msi \
+ --disable-pie \
+ --disable-modules \
+ --disable-module-upgrades \
+ --disable-debug-tcg \
+ --disable-debug-info \
+ --disable-sparse \
+ --disable-gnutls \
+ --disable-nettle \
+ --disable-gcrypt \
+ --disable-auth-pam \
+ --disable-sdl \
+ --disable-sdl-image \
+ --disable-gtk \
+ --disable-vte \
+ --disable-curses \
+ --disable-iconv \
+ --disable-vnc \
+ --disable-vnc-sasl \
+ --disable-vnc-jpeg \
+ --disable-vnc-png \
+ --disable-cocoa \
+ --disable-virtfs \
+ --disable-mpath \
+ --disable-xen \
+ --disable-xen-pci-passthrough \
+ --disable-brlapi \
+ --disable-curl \
+ --disable-membarrier \
+ --disable-fdt \
+ --disable-kvm \
+ --disable-hax \
+ --disable-hvf \
+ --disable-whpx \
+ --disable-rdma \
+ --disable-pvrdma \
+ --disable-vde \
+ --disable-netmap \
+ --disable-linux-aio \
+ --disable-linux-io-uring \
+ --disable-cap-ng \
+ --disable-attr \
+ --disable-vhost-net \
+ --disable-vhost-vsock \
+ --disable-vhost-scsi \
+ --disable-vhost-crypto \
+ --disable-vhost-kernel \
+ --disable-vhost-user \
+ --disable-spice \
+ --disable-rbd \
+ --disable-libiscsi \
+ --disable-libnfs \
+ --disable-smartcard \
+ --disable-libusb \
+ --disable-live-block-migration \
+ --disable-usb-redir \
+ --disable-lzo \
+ --disable-snappy \
+ --disable-bzip2 \
+ --disable-lzfse \
+ --disable-zstd \
+ --disable-seccomp \
+ --disable-coroutine-pool \
+ --disable-glusterfs \
+ --disable-tpm \
+ --disable-libssh \
+ --disable-numa \
+ --disable-libxml2 \
+ --disable-tcmalloc \
+ --disable-jemalloc \
+ --disable-avx2 \
+ --disable-avx512f \
+ --disable-replication \
+ --disable-opengl \
+ --disable-virglrenderer \
+ --disable-xfsctl \
+ --disable-qom-cast-debug \
+ --enable-tools \
+ --disable-vxhs \
+ --disable-bochs \
+ --disable-cloop \
+ --disable-dmg \
+ --disable-qcow1 \
+ --disable-vdi \
+ --disable-vvfat \
+ --disable-qed \
+ --disable-parallels \
+ --disable-sheepdog \
+ --disable-crypto-afalg \
+ --disable-capstone \
+ --disable-debug-mutex \
+ --disable-libpmem \
+ --disable-xkbcommon
+
+post-install:
+ @${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/qemu-*
+ @${RM} ${STAGEDIR}${PREFIX}/bin/qemu-nbd
+ @${RM} ${STAGEDIR}${PREFIX}/bin/qemu-edid
+ @${RM} ${STAGEDIR}${PREFIX}/bin/qemu-img
+ @${RM} ${STAGEDIR}${PREFIX}/bin/qemu-io
+ @${RMDIR} ${STAGEDIR}${DATADIR}
+ ${MKDIR} ${STAGEDIR}${PREFIX}/qemu
+
+.include <bsd.port.options.mk>
+
+.if !defined(STRIP) || ${STRIP} == ""
+CONFIGURE_ARGS+=--disable-strip
+.endif
+
+.if ${ARCH} == "amd64"
+MAKE_ARGS+= ARCH=x86_64
+.endif
+
+.if ${ARCH} == "powerpc"
+MAKE_ARGS+= ARCH=ppc
+.endif
+
+.if ${ARCH} == "powerpc64"
+MAKE_ARGS+= ARCH=ppc64
+.endif
+
+.if ${ARCH} == "sparc64"
+CONFIGURE_ARGS+= --sparc_cpu=v9
+.endif
+
+.if ${OSVERSION} < 1200000
+PKGMESSAGE= ${.CURDIR}/pkg-message-11
+.else
+PKGMESSAGE= ${.CURDIR}/pkg-message
+.endif
+
+PLIST_SUB+= LINUXBOOT_DMA=""
+
+# XXX need to disable usb host code on head while it's not ported to the
+# new usb stack yet
+post-configure:
+ @${REINPLACE_CMD} -E \
+ -e "s|^(HOST_USB=)bsd|\1stub|" \
+ ${WRKSRC}/config-host.mak
+
+.include <bsd.port.mk>
diff --git a/emulators/qemu-guest-agent/distinfo b/emulators/qemu-guest-agent/distinfo
new file mode 100644
index 000000000000..d5f50ec2c84a
--- /dev/null
+++ b/emulators/qemu-guest-agent/distinfo
@@ -0,0 +1,7 @@
+TIMESTAMP = 1603483758
+SHA256 (qemu/5.0.1/qemu-5.0.1.tar.xz) = 135fab4c3699a378c9584b3453927e2f5002e440311f21efa66fc189d4bb4982
+SIZE (qemu/5.0.1/qemu-5.0.1.tar.xz) = 62430168
+SHA256 (qemu/5.0.1/55765822804f.patch) = 10c2cc93ad01b02d854e26a9e445ba22bb5434dda1ef25baeb979be6292fa8ef
+SIZE (qemu/5.0.1/55765822804f.patch) = 2271
+SHA256 (qemu/5.0.1/aa4d30f6618d.patch) = eeddc5f5e08a460d2c133b4193d115fa1f00f206e0833f33ec66379981473efe
+SIZE (qemu/5.0.1/aa4d30f6618d.patch) = 2211
diff --git a/emulators/qemu-guest-agent/files/patch-Makefile b/emulators/qemu-guest-agent/files/patch-Makefile
new file mode 100644
index 000000000000..3520d14c1d94
--- /dev/null
+++ b/emulators/qemu-guest-agent/files/patch-Makefile
@@ -0,0 +1,106 @@
+--- Makefile.orig 2020-09-15 19:31:13 UTC
++++ Makefile
+@@ -361,29 +361,6 @@
+ MANUAL_BUILDDIR := docs
+ endif
+
+-ifdef BUILD_DOCS
+-DOCS+=$(MANUAL_BUILDDIR)/system/qemu.1
+-DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-img.1
+-DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-nbd.8
+-DOCS+=$(MANUAL_BUILDDIR)/interop/qemu-ga.8
+-ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
+-DOCS+=$(MANUAL_BUILDDIR)/tools/virtiofsd.1
+-endif
+-DOCS+=$(MANUAL_BUILDDIR)/system/qemu-block-drivers.7
+-DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
+-DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7
+-DOCS+=$(MANUAL_BUILDDIR)/system/qemu-cpu-models.7
+-DOCS+=$(MANUAL_BUILDDIR)/index.html
+-ifdef CONFIG_VIRTFS
+-DOCS+=$(MANUAL_BUILDDIR)/tools/virtfs-proxy-helper.1
+-endif
+-ifdef CONFIG_TRACE_SYSTEMTAP
+-DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-trace-stap.1
+-endif
+-else
+-DOCS=
+-endif
+-
+ SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet) BUILD_DIR=$(BUILD_DIR)
+ SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(filter %-softmmu, $(TARGET_DIRS)))
+ SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %.d, $(SUBDIR_DEVICES_MAK))
+@@ -878,10 +855,6 @@
+ $(call install-manual,user)
+
+ install-doc: $(DOCS) install-sphinxdocs
+- $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
+- $(INSTALL_DATA) $(MANUAL_BUILDDIR)/index.html "$(DESTDIR)$(qemu_docdir)"
+- $(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)"
+- $(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)"
+ ifdef CONFIG_POSIX
+ $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
+ $(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu.1 "$(DESTDIR)$(mandir)/man1"
+@@ -889,21 +862,10 @@
+ $(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7"
+ $(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7"
+ $(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu-cpu-models.7 "$(DESTDIR)$(mandir)/man7"
+-ifeq ($(CONFIG_TOOLS),y)
+- $(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-img.1 "$(DESTDIR)$(mandir)/man1"
+- $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
+- $(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
+-endif
+ ifdef CONFIG_TRACE_SYSTEMTAP
+ $(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-trace-stap.1 "$(DESTDIR)$(mandir)/man1"
+ endif
+-ifneq (,$(findstring qemu-ga,$(TOOLS)))
+- $(INSTALL_DATA) $(MANUAL_BUILDDIR)/interop/qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
+- $(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
+- $(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)"
+- $(INSTALL_DATA) docs/interop/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
+ endif
+-endif
+ ifdef CONFIG_VIRTFS
+ $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
+ $(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
+@@ -927,7 +889,7 @@
+ install-includedir:
+ $(INSTALL_DIR) "$(DESTDIR)$(includedir)"
+
+-install: all $(if $(BUILD_DOCS),install-doc) \
++install: all \
+ install-datadir install-localstatedir install-includedir \
+ $(if $(INSTALL_BLOBS),$(edk2-decompressed)) \
+ recurse-install
+@@ -974,31 +936,12 @@
+ "$(DESTDIR)$(qemu_datadir)/firmware/$$x"; \
+ done
+ endif
+- for s in $(ICON_SIZES); do \
+- mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/$${s}/apps"; \
+- $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_$${s}.png \
+- "$(DESTDIR)$(qemu_icondir)/hicolor/$${s}/apps/qemu.png"; \
+- done; \
+- mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/32x32/apps"; \
+- $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_32x32.bmp \
+- "$(DESTDIR)$(qemu_icondir)/hicolor/32x32/apps/qemu.bmp"; \
+- mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/scalable/apps"; \
+- $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu.svg \
+- "$(DESTDIR)$(qemu_icondir)/hicolor/scalable/apps/qemu.svg"
+- mkdir -p "$(DESTDIR)$(qemu_desktopdir)"
+- $(INSTALL_DATA) $(SRC_PATH)/ui/qemu.desktop \
+- "$(DESTDIR)$(qemu_desktopdir)/qemu.desktop"
+ ifdef CONFIG_GTK
+ $(MAKE) -C po $@
+ endif
+ ifeq ($(CONFIG_PLUGIN),y)
+ $(INSTALL_DATA) $(SRC_PATH)/include/qemu/qemu-plugin.h "$(DESTDIR)$(includedir)/qemu-plugin.h"
+ endif
+- $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
+- set -e; for x in $(KEYMAPS); do \
+- $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
+- done
+- $(INSTALL_DATA) $(BUILD_DIR)/trace-events-all "$(DESTDIR)$(qemu_datadir)/trace-events-all"
+
+ .PHONY: ctags
+ ctags:
diff --git a/emulators/qemu-guest-agent/files/patch-configure b/emulators/qemu-guest-agent/files/patch-configure
new file mode 100644
index 000000000000..adf14fe21462
--- /dev/null
+++ b/emulators/qemu-guest-agent/files/patch-configure
@@ -0,0 +1,201 @@
+--- configure.orig 2020-09-15 19:31:13 UTC
++++ configure
+@@ -360,7 +360,7 @@
+ sdl=""
+ sdl_image=""
+ virtfs=""
+-mpath=""
++mpath="no"
+ vnc="yes"
+ sparse="no"
+ vde=""
+@@ -408,7 +408,7 @@
+ modules="no"
+ module_upgrades="no"
+ prefix="/usr/local"
+-mandir="\${prefix}/share/man"
++mandir="\${prefix}/man"
+ datadir="\${prefix}/share"
+ firmwarepath="\${prefix}/share/qemu-firmware"
+ qemu_docdir="\${prefix}/share/doc/qemu"
+@@ -493,6 +493,9 @@
+ tcmalloc="no"
+ jemalloc="no"
+ replication="yes"
++pcap="no"
++pcap_create="no"
++bpf="no"
+ vxhs=""
+ bochs="yes"
+ cloop="yes"
+@@ -509,6 +512,7 @@
+ default_devices="yes"
+ plugins="no"
+ fuzzing="no"
++libudev="no"
+
+ supported_cpu="no"
+ supported_os="no"
+@@ -904,7 +908,7 @@
+ kvm="yes"
+ QEMU_INCLUDES="-isystem \$(SRC_PATH)/linux-headers -isystem $PWD/linux-headers $QEMU_INCLUDES"
+ supported_os="yes"
+- libudev="yes"
++ libudev="no"
+ ;;
+ esac
+
+@@ -1168,6 +1172,10 @@
+ ;;
+ --enable-vnc-png) vnc_png="yes"
+ ;;
++ --enable-pcap) pcap="yes"
++ ;;
++ --disable-pcap) pcap="no"
++ ;;
+ --disable-slirp) slirp="no"
+ ;;
+ --enable-slirp=git) slirp="git"
+@@ -3137,6 +3145,14 @@
+ fi
+
+ ##########################################
++# getifaddrs (for tests/test-io-channel-socket )
++
++have_ifaddrs_h=yes
++if ! check_include "ifaddrs.h" ; then
++ have_ifaddrs_h=no
++fi
++
++##########################################
+ # VTE probe
+
+ if test "$vte" != "no"; then
+@@ -3806,7 +3822,7 @@
+ glib_libs=$($pkg_config --libs $i)
+ QEMU_CFLAGS="$glib_cflags $QEMU_CFLAGS"
+ LIBS="$glib_libs $LIBS"
+- libs_qga="$glib_libs $libs_qga"
++ libs_qga="$glib_libs -lintl $libs_qga"
+ else
+ error_exit "glib-$glib_req_ver $i is required to compile QEMU"
+ fi
+@@ -3926,7 +3942,7 @@
+ ##########################################
+ # pixman support probe
+
+-if test "$want_tools" = "no" && test "$softmmu" = "no"; then
++if test "$softmmu" = "no"; then
+ pixman_cflags=
+ pixman_libs=
+ elif $pkg_config --atleast-version=0.21.8 pixman-1 > /dev/null 2>&1; then
+@@ -4957,14 +4973,6 @@
+ fi
+ if has makeinfo && has pod2man && test "$sphinx_ok" = "yes"; then
+ docs=yes
+- else
+- if test "$docs" = "yes" ; then
+- if has $sphinx_build && test "$sphinx_ok" != "yes"; then
+- echo "Warning: $sphinx_build exists but it is either too old or uses too old a Python version" >&2
+- fi
+- feature_not_found "docs" "Install texinfo, Perl/perl-podlators and a Python 3 version of python-sphinx"
+- fi
+- docs=no
+ fi
+ fi
+
+@@ -5098,7 +5106,7 @@
+
+ # check for libusb
+ if test "$libusb" != "no" ; then
+- if $pkg_config --atleast-version=1.0.13 libusb-1.0; then
++ if $pkg_config libusb-1.0; then
+ libusb="yes"
+ libusb_cflags=$($pkg_config --cflags libusb-1.0)
+ libusb_libs=$($pkg_config --libs libusb-1.0)
+@@ -5501,7 +5509,51 @@
+ fi
+ fi
+
++##########################################
++# pcap probe
+
++if test "$pcap" = "yes" -a "$pcap" != "no"; then
++ cat > $TMPC << EOF
++#include <pcap.h>
++int main(void) { return (pcap_lib_version() == (char *)0 ? 1 : 0); }
++EOF
++ if test "$mingw32" = "no" ; then
++ libpcap=-lpcap
++ else
++ libpcap=-lwpcap
++ fi
++ if compile_prog "" "$libpcap" ; then
++ :
++ else
++ echo
++ echo "Error: Could not find pcap"
++ echo "Make sure to have the pcap libs and headers installed."
++ echo
++ exit 1
++ fi
++ cat > $TMPC << EOF
++#include <pcap.h>
++int main(void)
++{
++ char errbuf[PCAP_ERRBUF_SIZE];
++ return (pcap_create("foo", errbuf) == (pcap_t *)0 ? 1 : 0);
++}
++EOF
++ if compile_prog "" "$libpcap" ; then
++ pcap_create="yes"
++ fi
++ cat > $TMPC << EOF
++#define PCAP_DONT_INCLUDE_PCAP_BPF_H
++#include <pcap.h>
++#include <net/bpf.h>
++int main(void) { return (BPF_MAJOR_VERSION); }
++EOF
++ if compile_prog ; then
++ bpf="yes"
++ fi
++ libs_softmmu="$libpcap $libs_softmmu"
++fi # test "$pcap"
++
+ ##########################################
+ # check if we have open_by_handle_at
+
+@@ -6627,6 +6679,7 @@
+ echo "Block whitelist (rw) $block_drv_rw_whitelist"
+ echo "Block whitelist (ro) $block_drv_ro_whitelist"
+ echo "VirtFS support $virtfs"
++echo "pcap support $pcap"
+ echo "Multipath support $mpath"
+ echo "VNC support $vnc"
+ if test "$vnc" = "yes" ; then
+@@ -6864,6 +6917,15 @@
+ if test "$want_tools" = "yes" ; then
+ echo "CONFIG_TOOLS=y" >> $config_host_mak
+ fi
++if test "$pcap" = "yes" ; then
++ echo "CONFIG_PCAP=y" >> $config_host_mak
++ if test "$pcap_create" = "yes" ; then
++ echo "CONFIG_PCAP_CREATE=y" >> $config_host_mak
++ fi
++ if test "$bpf" = "yes" ; then
++ echo "CONFIG_BPF=y" >> $config_host_mak
++ fi
++fi
+ if test "$slirp" != "no"; then
+ echo "CONFIG_SLIRP=y" >> $config_host_mak
+ echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak
+@@ -7120,6 +7182,9 @@
+ # if this macro is set.
+ if test "$have_fsxattr" = "yes" ; then
+ echo "HAVE_FSXATTR=y" >> $config_host_mak
++fi
++if test "$have_ifaddrs_h" = "yes" ; then
++ echo "HAVE_IFADDRS_H=y" >> $config_host_mak
+ fi
+ if test "$have_copy_file_range" = "yes" ; then
+ echo "HAVE_COPY_FILE_RANGE=y" >> $config_host_mak
diff --git a/emulators/qemu-guest-agent/files/patch-qga_commands-posix.c b/emulators/qemu-guest-agent/files/patch-qga_commands-posix.c
new file mode 100644
index 000000000000..11dce8e5b8fc
--- /dev/null
+++ b/emulators/qemu-guest-agent/files/patch-qga_commands-posix.c
@@ -0,0 +1,758 @@
+--- qga/commands-posix.c.orig 2020-09-15 16:31:14 UTC
++++ qga/commands-posix.c
+@@ -28,6 +28,21 @@
+ #include "qemu/cutils.h"
+ #include "commands-common.h"
+
++#ifdef BSD_GUEST_AGENT
++#include <ifaddrs.h>
++#include <arpa/inet.h>
++#include <sys/socket.h>
++#include <sys/sysctl.h>
++#include <net/if.h>
++#include <sys/socket.h>
++#include <ifaddrs.h>
++#include <sys/statvfs.h>
++#include <net/if_dl.h>
++#include <net/if_types.h>
++#include <net/ethernet.h>
++#include <net/if_var.h>
++#endif
++
+ #ifdef HAVE_UTMPX
+ #include <utmpx.h>
+ #endif
+@@ -85,14 +100,25 @@ void qmp_guest_shutdown(bool has_mode, const char *mod
+ {
+ const char *shutdown_flag;
+ Error *local_err = NULL;
++#ifdef BSD_GUEST_AGENT
++ char *shutdown_mode;
++#endif // BSD_GUEST_AGENT
+ pid_t pid;
+ int status;
+
+ slog("guest-shutdown called, mode: %s", mode);
+ if (!has_mode || strcmp(mode, "powerdown") == 0) {
++#ifdef BSD_GUEST_AGENT
++ shutdown_flag = "-p";
++#else
+ shutdown_flag = "-P";
++#endif // BSD_GUEST_AGENT
+ } else if (strcmp(mode, "halt") == 0) {
++#ifdef BSD_GUEST_AGENT
++ shutdown_flag = "-h";
++#else
+ shutdown_flag = "-H";
++#endif // BSD_GUEST_AGENT
+ } else if (strcmp(mode, "reboot") == 0) {
+ shutdown_flag = "-r";
+ } else {
+@@ -108,9 +134,15 @@ void qmp_guest_shutdown(bool has_mode, const char *mod
+ reopen_fd_to_null(0);
+ reopen_fd_to_null(1);
+ reopen_fd_to_null(2);
++#ifdef BSD_GUEST_AGENT
++ shutdown_mode = g_strdup_printf("hypervisor initiated %s", mode);
+
++ execle("/sbin/shutdown", "-h", shutdown_flag, "+0",
++ shutdown_mode, (char*)NULL, environ);
++#else
+ execle("/sbin/shutdown", "shutdown", "-h", shutdown_flag, "+0",
+ "hypervisor initiated shutdown", (char*)NULL, environ);
++#endif // BSD_GUEST_AGENT
+ _exit(EXIT_FAILURE);
+ } else if (pid < 0) {
+ error_setg_errno(errp, errno, "failed to create child process");
+@@ -153,9 +185,11 @@ int64_t qmp_guest_get_time(Error **errp)
+ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
+ {
+ int ret;
++#ifndef BSD_GUEST_AGENT
+ int status;
+ pid_t pid;
+ Error *local_err = NULL;
++#endif
+ struct timeval tv;
+ static const char hwclock_path[] = "/sbin/hwclock";
+ static int hwclock_available = -1;
+@@ -193,7 +227,7 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns
+ return;
+ }
+ }
+-
++#ifndef BSD_GUEST_AGENT
+ /* Now, if user has passed a time to set and the system time is set, we
+ * just need to synchronize the hardware clock. However, if no time was
+ * passed, user is requesting the opposite: set the system time from the
+@@ -230,6 +264,7 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns
+ error_setg(errp, "hwclock failed to set hardware clock to system time");
+ return;
+ }
++#endif // BSD_GUEST_AGENT
+ }
+
+ typedef enum {
+@@ -2625,25 +2660,263 @@ void qmp_guest_suspend_hybrid(Error **errp)
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+ }
+-
++#ifndef BSD_GUEST_AGENT
+ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+ return NULL;
+ }
++#else
++static GuestNetworkInterfaceList *
++guest_find_interface(GuestNetworkInterfaceList *head,
++ const char *name)
++{
++ for (; head; head = head->next) {
++ if (strcmp(head->value->name, name) == 0) {
++ break;
++ }
++ }
+
++ return head;
++}
++
++static int guest_get_network_stats(const char *name,
++ GuestNetworkInterfaceStat *stats)
++{
++ return -1;
++}
++
++GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
++{
++ GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
++ struct ifaddrs *ifap, *ifa;
++
++ if (getifaddrs(&ifap) < 0) {
++ error_setg_errno(errp, errno, "getifaddrs failed");
++ goto error;
++ }
++
++ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
++ GuestNetworkInterfaceList *info;
++ GuestIpAddressList **address_list = NULL, *address_item = NULL;
++ GuestNetworkInterfaceStat *interface_stat = NULL;
++ char addr4[INET_ADDRSTRLEN];
++ char addr6[INET6_ADDRSTRLEN];
++ int sock;
++ struct ifreq ifr;
++ // struct ifnet ifp;
++ // struct if_data ifd;
++ // unsigned char *mac_addr;
++ char mac_addr[18]="00:00:00:00:00:00"; // = char[18];
++ void *p;
++
++ g_debug("Processing %s interface", ifa->ifa_name);
++
++ info = guest_find_interface(head, ifa->ifa_name);
++
++ if (!info) {
++ info = g_malloc0(sizeof(*info));
++ info->value = g_malloc0(sizeof(*info->value));
++ info->value->name = g_strdup(ifa->ifa_name);
++
++ if (!cur_item) {
++ head = cur_item = info;
++ } else {
++ cur_item->next = info;
++ cur_item = info;
++ }
++ }
++
++ if (!info->value->has_hardware_address &&
++ ifa->ifa_flags & SIOCGHWADDR) {
++ /* we haven't obtained HW address yet */
++ sock = socket(PF_INET, SOCK_STREAM, 0);
++ if (sock == -1) {
++ error_setg_errno(errp, errno, "failed to create socket");
++ goto error;
++ }
++ close(sock);
++
++ memset(&ifr, 0, sizeof(ifr));
++ pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
++ // memset(&ifp, 0, sizeof(ifp));
++ // memset(&ifd, 0, sizeof(ifd));
++
++ if (ifa->ifa_addr->sa_family == AF_LINK) {
++ struct sockaddr_dl *sdl =
++ (struct sockaddr_dl *)ifa->ifa_addr;
++
++ info->value->has_hardware_address = false;
++
++ if (sdl->sdl_type == IFT_ETHER &&
++ sdl->sdl_alen == ETHER_ADDR_LEN) {
++ snprintf(mac_addr, 18, "%s", ether_ntoa((struct ether_addr *)LLADDR(sdl)));
++ info->value->has_hardware_address = true;
++ }
++ else
++ {
++ info->value->has_hardware_address = true;
++ }
++ info->value->hardware_address = g_strdup_printf("%s", mac_addr);
++ }
++
++ }
++
++ if (ifa->ifa_addr &&
++ ifa->ifa_addr->sa_family == AF_INET) {
++ /* interface with IPv4 address */
++ p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
++ if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
++ error_setg_errno(errp, errno, "inet_ntop failed");
++ goto error;
++ }
++
++ address_item = g_malloc0(sizeof(*address_item));
++ address_item->value = g_malloc0(sizeof(*address_item->value));
++ address_item->value->ip_address = g_strdup(addr4);
++ address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
++
++ if (ifa->ifa_netmask) {
++ /* Count the number of set bits in netmask.
++ * This is safe as '1' and '0' cannot be shuffled in netmask. */
++ p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
++ address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
++ }
++ } else if (ifa->ifa_addr &&
++ ifa->ifa_addr->sa_family == AF_INET6) {
++ /* interface with IPv6 address */
++ p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
++ if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
++ error_setg_errno(errp, errno, "inet_ntop failed");
++ goto error;
++ }
++
++ address_item = g_malloc0(sizeof(*address_item));
++ address_item->value = g_malloc0(sizeof(*address_item->value));
++ address_item->value->ip_address = g_strdup(addr6);
++ address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
++
++ if (ifa->ifa_netmask) {
++ /* Count the number of set bits in netmask.
++ * This is safe as '1' and '0' cannot be shuffled in netmask. */
++ p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
++ address_item->value->prefix =
++ ctpop32(((uint32_t *) p)[0]) +
++ ctpop32(((uint32_t *) p)[1]) +
++ ctpop32(((uint32_t *) p)[2]) +
++ ctpop32(((uint32_t *) p)[3]);
++ }
++ }
++
++ if (!address_item) {
++ continue;
++ }
++
++ address_list = &info->value->ip_addresses;
++
++ while (*address_list && (*address_list)->next) {
++ address_list = &(*address_list)->next;
++ }
++
++ if (!*address_list) {
++ *address_list = address_item;
++ } else {
++ (*address_list)->next = address_item;
++ }
++
++ info->value->has_ip_addresses = true;
++
++ if (!info->value->has_statistics) {
++ interface_stat = g_malloc0(sizeof(*interface_stat));
++ if (guest_get_network_stats(info->value->name,
++ interface_stat) == -1) {
++ info->value->has_statistics = false;
++ g_free(interface_stat);
++ } else {
++ info->value->statistics = interface_stat;
++ info->value->has_statistics = true;
++ }
++ }
++ }
++
++ freeifaddrs(ifap);
++ return head;
++
++error:
++ freeifaddrs(ifap);
++ qapi_free_GuestNetworkInterfaceList(head);
++ return NULL;
++}
++#endif // BSD_GUEST_AGENT
++
++#ifndef BSD_GUEST_AGENT
+ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+ return NULL;
+ }
++#else
++GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
++{
++ int64_t current;
++ GuestLogicalProcessorList *head, **link;
++ long sc_max;
++ Error *local_err = NULL;
++ int Query[2];
++ int NumCpu = 0;
++ size_t Length = sizeof(NumCpu);
++ Query[0] = CTL_HW;
++ Query[1] = HW_NCPU;
+
++ current = 0;
++ head = NULL;
++ link = &head;
++ if (sysctl(Query, 2, &NumCpu, &Length, NULL, 0) == -1) {
++ error_setg(errp, "sysctl get CTL_HW.HW_NCPU failed");
++ }
++ sc_max = NumCpu;
++
++ while (local_err == NULL && current < sc_max) {
++ GuestLogicalProcessor *vcpu;
++ GuestLogicalProcessorList *entry;
++ int64_t id = current++;
++ // char *path = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
++ // id);
++
++ // if (g_file_test(path, G_FILE_TEST_EXISTS)) {
++ vcpu = g_malloc0(sizeof *vcpu);
++ vcpu->logical_id = id;
++ vcpu->has_can_offline = false; /* lolspeak ftw */
++ vcpu->online = true;
++ vcpu->can_offline = false;
++ // transfer_vcpu(vcpu, true, path, &local_err);
++ entry = g_malloc0(sizeof *entry);
++ entry->value = vcpu;
++ *link = entry;
++ link = &entry->next;
++ // }
++ // g_free(path);
++ }
++
++ if (local_err == NULL) {
++ /* there's no guest with zero VCPUs */
++ g_assert(head != NULL);
++ return head;
++ }
++
++ qapi_free_GuestLogicalProcessorList(head);
++ error_propagate(errp, local_err);
++ return NULL;
++}
++#endif // BSD_GUEST_AGENT
++
+ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+ return -1;
+ }
+
++#ifndef BSD_GUEST_AGENT
+ void qmp_guest_set_user_password(const char *username,
+ const char *password,
+ bool crypted,
+@@ -2651,7 +2924,114 @@ void qmp_guest_set_user_password(const char *username,
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+ }
++#else
++void qmp_guest_set_user_password(const char *username,
++ const char *password,
++ bool crypted,
++ Error **errp)
++{
++ Error *local_err = NULL;
++ char *pw_path = NULL;
++ pid_t pid;
++ int status;
++ int datafd[2] = { -1, -1 };
++ char *rawpasswddata = NULL;
++ size_t rawpasswdlen;
++ char *chpasswddata = NULL;
++ size_t chpasswdlen;
+
++ rawpasswddata = (char *)qbase64_decode(password, -1, &rawpasswdlen, errp);
++ if (!rawpasswddata) {
++ return;
++ }
++
++ rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
++ rawpasswddata[rawpasswdlen] = '\0';
++
++ if (strchr(rawpasswddata, '\n')) {
++ error_setg(errp, "forbidden characters in raw password");
++ goto out;
++ }
++
++ if (strchr(username, '\n') ||
++ strchr(username, ':')) {
++ error_setg(errp, "forbidden characters in username");
++ goto out;
++ }
++
++ chpasswddata = g_strdup_printf("%s", rawpasswddata);
++ chpasswdlen = strlen(chpasswddata);
++
++ pw_path = g_find_program_in_path("pw");
++
++ if (!pw_path) {
++ error_setg(errp, "cannot find 'pw' program in PATH");
++ goto out;
++ }
++
++ if (pipe(datafd) < 0) {
++ error_setg(errp, "cannot create pipe FDs");
++ goto out;
++ }
++
++ pid = fork();
++ if (pid == 0) {
++ close(datafd[1]);
++ /* child */
++ setsid();
++ dup2(datafd[0], 0);
++ reopen_fd_to_null(1);
++ reopen_fd_to_null(2);
++
++ if (crypted) {
++ execle(pw_path, "pw", "usermod", username, "-H", "0", (char*)NULL, environ);
++ } else {
++ execle(pw_path, "pw", "usermod", username, "-h", "0", (char*)NULL, environ);
++ }
++ _exit(EXIT_FAILURE);
++ } else if (pid < 0) {
++ error_setg_errno(errp, errno, "failed to create child process");
++ goto out;
++ }
++ close(datafd[0]);
++ datafd[0] = -1;
++
++ if (qemu_write_full(datafd[1], chpasswddata, chpasswdlen) != chpasswdlen) {
++ error_setg_errno(errp, errno, "cannot write new account password");
++ goto out;
++ }
++ close(datafd[1]);
++ datafd[1] = -1;
++
++ ga_wait_child(pid, &status, &local_err);
++ if (local_err) {
++ error_propagate(errp, local_err);
++ goto out;
++ }
++
++ if (!WIFEXITED(status)) {
++ error_setg(errp, "child process has terminated abnormally");
++ goto out;
++ }
++
++ if (WEXITSTATUS(status)) {
++ error_setg(errp, "child process has failed to set user password");
++ goto out;
++ }
++
++out:
++ g_free(chpasswddata);
++ g_free(rawpasswddata);
++ g_free(pw_path);
++ if (datafd[0] != -1) {
++ close(datafd[0]);
++ }
++ if (datafd[1] != -1) {
++ close(datafd[1]);
++ }
++}
++#endif // BSD_GUEST_AGENT
++
+ GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+@@ -2675,12 +3055,240 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(
+
+ #if !defined(CONFIG_FSFREEZE)
+
++#ifndef BSD_GUEST_AGENT
+ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+ return NULL;
+ }
++#else
+
++/* ===================================================================== */
++typedef struct FsMount {
++ char *dirname;
++ char *devtype;
++ char *size;
++ char *used;
++ char *free;
++ char *load;
++ char *mntpoint;
++ unsigned int devmajor, devminor;
++ QTAILQ_ENTRY(FsMount) next;
++} FsMount;
++
++typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList;
++
++static void free_fs_mount_list(FsMountList *mounts)
++{
++ FsMount *mount, *temp;
++
++ if (!mounts) {
++ return;
++ }
++
++ QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
++ QTAILQ_REMOVE(mounts, mount, next);
++ g_free(mount->dirname);
++ g_free(mount->devtype);
++ g_free(mount->size);
++ g_free(mount->used);
++ g_free(mount->free);
++ g_free(mount->load);
++ g_free(mount->mntpoint);
++ g_free(mount);
++ }
++}
++
++
++#define BUFSIZE 2048
++
++static void build_fs_mount_list(FsMountList *mounts, Error **errp)
++{
++ FsMount *mount;
++ char const *dfcmd = "/bin/df -hT";
++ //char buf[BUFSIZE];
++
++ FILE *fp;
++ char *line = NULL;
++ //, *dash;
++ size_t n;
++ int ret;
++ //, dir_s, dir_e, type_s, type_e, dev_s, dev_e;
++ char dev_name[30], fstype[10], size[10], used[10], free[10], load[10], mounted[30];
++ //int dev_name, fstype, size, used, free, load, mounted;
++
++ if ((fp = popen(dfcmd, "r")) == NULL) {
++ g_debug("Cannot open '%s'!!\n", dfcmd);
++ return;
++ }
++ while (getline(&line, &n, fp) != -1) {
++ //g_debug("line '%s'", line);
++ ret = sscanf(line, "%s%s%s%s%s%s%s",
++ dev_name, fstype, size, used, free, load, mounted);
++ if (g_str_equal(dev_name, "Filesystem")
++ ||g_str_equal(fstype,"devfs")
++ ||g_str_equal(fstype,"procfs")
++ ||g_str_equal(fstype,"fdescfs")) {
++ continue;
++ }
++ //g_debug("ret '%d'", ret);
++
++ if (ret < 7) {
++ continue;
++ }
++ mount = g_new0(FsMount, 1);
++ mount->dirname = g_strdup(dev_name);
++ mount->devtype = g_strdup(fstype);
++ mount->free = g_strdup(free);
++ mount->load = g_strdup(load);
++ mount->size = g_strdup(size);
++ mount->used = g_strdup(used);
++ mount->mntpoint = g_strdup(mounted);
++ mount->devmajor = 0;
++ mount->devminor = 0;
++
++ QTAILQ_INSERT_TAIL(mounts, mount, next);
++ }
++ //free(line);
++
++ fclose(fp);
++}
++
++/* ======================================================= */
++
++
++/* Return a list of the disk device(s)' info which @mount lies on */
++static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
++ Error **errp)
++{
++ GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
++ struct statvfs buf;
++ unsigned long used, nonroot_total, fr_size;
++
++ fs->name = g_strdup(mount->dirname);
++ fs->mountpoint = g_strdup(mount->mntpoint);
++ fs->type = g_strdup(mount->devtype);
++
++ /*
++ * if you need extended structure like this
++ *
++ {
++ "name": "/dev/vtbd0p2",
++ "total-bytes": 9079570432,
++ "mountpoint": "/",
++ "disk": [
++ {
++ "serial": "serial",
++ "bus-type": "virtio",
++ "bus": 0,
++ "unit": 0,
++ "pci-controller": {
++ "bus": 0,
++ "slot": 0,
++ "domain": 0,
++ "function": 0
++ },
++ "dev": "/dev/vtbd0p2",
++ "target": 0
++ }
++ ],
++ "used-bytes": 7378640896,
++ "type": "ufs"
++ }
++
++ instead
++
++ {
++ "name": "/dev/vtbd0p2",
++ "total-bytes": 9079570432,
++ "mountpoint": "/",
++ "disk": [],
++ "used-bytes": 7378747392,
++ "type": "ufs"
++ }
++
++ uncomment next block with pciaddr
++
++ */
++ /*
++ GuestPCIAddress *pciaddr = NULL;
++ GuestDiskAddressList *list = NULL;
++ GuestDiskAddress *disk;
++ pciaddr = g_malloc0(sizeof(*pciaddr));
++ pciaddr->domain = 0;
++ pciaddr->bus = 0;
++ pciaddr->slot = 0;
++ pciaddr->function = 0;
++
++ disk = g_malloc0(sizeof(*disk));
++ disk->pci_controller = pciaddr;
++
++ disk->dev = g_strdup(mount->dirname);
++ disk->has_dev = true;
++ disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
++ disk->serial = g_strdup("serial");
++ disk->has_serial = true;
++
++ list = g_malloc0(sizeof(*list));
++ list->value = disk;
++
++ list->next = fs->disk;
++ fs->disk = list;
++ */
++
++ if (statvfs(fs->mountpoint, &buf) == 0) {
++ fr_size = buf.f_frsize;
++ used = buf.f_blocks - buf.f_bfree;
++ nonroot_total = used + buf.f_bavail;
++ fs->used_bytes = used * fr_size;
++ fs->total_bytes = nonroot_total * fr_size;
++
++ fs->has_total_bytes = true;
++ fs->has_used_bytes = true;
++ }
++
++ //g_free(devpath);
++
++ return fs;
++}
++
++GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
++{
++ FsMountList mounts;
++ struct FsMount *mount;
++ GuestFilesystemInfoList *new, *ret = NULL;
++ Error *local_err = NULL;
++
++ QTAILQ_INIT(&mounts);
++
++ //g_debug("Entering to guest_get_fsinfo");
++ build_fs_mount_list(&mounts, &local_err);
++ if (local_err) {
++ error_propagate(errp, local_err);
++ return NULL;
++ }
++
++
++ QTAILQ_FOREACH(mount, &mounts, next) {
++ //g_debug("Building guest fsinfo for '%s'", mount->dirname);
++ //g_debug("Devtype '%s'", mount->devtype);
++ new = g_malloc0(sizeof(*ret));
++ new->value = build_guest_fsinfo(mount, &local_err);
++ new->next = ret;
++ ret = new;
++ if (local_err) {
++ error_propagate(errp, local_err);
++ qapi_free_GuestFilesystemInfoList(ret);
++ ret = NULL;
++ break;
++ }
++ }
++
++ free_fs_mount_list(&mounts);
++ return ret;
++}
++#endif // BSD_GUEST_AGENT
++
+ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
+ {
+ error_setg(errp, QERR_UNSUPPORTED);
+@@ -2726,6 +3334,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
+ {
+ #if !defined(__linux__)
+ {
++#ifndef BSD_GUEST_AGENT
+ const char *list[] = {
+ "guest-suspend-disk", "guest-suspend-ram",
+ "guest-suspend-hybrid", "guest-network-get-interfaces",
+@@ -2733,6 +3342,15 @@ GList *ga_command_blacklist_init(GList *blacklist)
+ "guest-get-memory-blocks", "guest-set-memory-blocks",
+ "guest-get-memory-block-size", "guest-get-memory-block-info",
+ NULL};
++#else
++ const char *list[] = {
++ "guest-suspend-disk", "guest-suspend-ram",
++ "guest-suspend-hybrid",
++ "guest-set-vcpus",
++ "guest-get-memory-blocks", "guest-set-memory-blocks",
++ "guest-get-memory-block-size", "guest-get-memory-block-info",
++ NULL};
++#endif // BSD_GUEST_AGENT
+ char **p = (char **)list;
+
+ while (*p) {
+@@ -2743,10 +3361,17 @@ GList *ga_command_blacklist_init(GList *blacklist)
+
+ #if !defined(CONFIG_FSFREEZE)
+ {
++#ifndef BSD_GUEST_AGENT
+ const char *list[] = {
+ "guest-get-fsinfo", "guest-fsfreeze-status",
+ "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
+ "guest-fsfreeze-thaw", "guest-get-fsinfo", NULL};
++#else
++ const char *list[] = {
++ "guest-fsfreeze-status",
++ "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
++ "guest-fsfreeze-thaw", NULL};
++#endif // BSD_GUEST_AGENT
+ char **p = (char **)list;
+
+ while (*p) {
diff --git a/emulators/qemu-guest-agent/files/patch-qga_main.c b/emulators/qemu-guest-agent/files/patch-qga_main.c
new file mode 100644
index 000000000000..a7ee80a840c5
--- /dev/null
+++ b/emulators/qemu-guest-agent/files/patch-qga_main.c
@@ -0,0 +1,30 @@
+--- qga/main.c.orig 2020-09-15 16:31:14 UTC
++++ qga/main.c
+@@ -46,9 +46,15 @@
+ #endif
+
+ #ifndef _WIN32
++#ifdef BSD_GUEST_AGENT
++#define QGA_VIRTIO_PATH_DEFAULT "/dev/vtcon/org.qemu.guest_agent.0"
++#define QGA_STATE_RELATIVE_DIR "run"
++#define QGA_SERIAL_PATH_DEFAULT "/dev/vtcon/org.qemu.guest_agent.0"
++#else
+ #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
+ #define QGA_STATE_RELATIVE_DIR "run"
+ #define QGA_SERIAL_PATH_DEFAULT "/dev/ttyS0"
++#endif // BSD_GUEST_AGENT
+ #else
+ #define QGA_VIRTIO_PATH_DEFAULT "\\\\.\\Global\\org.qemu.guest_agent.0"
+ #define QGA_STATE_RELATIVE_DIR "qemu-ga"
+@@ -1478,7 +1484,11 @@ int main(int argc, char **argv)
+ }
+
+ if (config->method == NULL) {
++#ifdef BSD_GUEST_AGENT
++ config->method = g_strdup("isa-serial");
++#else
+ config->method = g_strdup("virtio-serial");
++#endif // BSD_GUEST_AGENT
+ }
+
+ socket_activation = check_socket_activation();
diff --git a/emulators/qemu-guest-agent/files/qemu-guest-agent.in b/emulators/qemu-guest-agent/files/qemu-guest-agent.in
new file mode 100644
index 000000000000..158666dbbc31
--- /dev/null
+++ b/emulators/qemu-guest-agent/files/qemu-guest-agent.in
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# PROVIDE: qemu_guest_agent
+# REQUIRE: DAEMON
+# KEYWORD: nojail
+#
+
+#
+# Add the following lines to /etc/rc.conf to enable qemu-guest-agent:
+#
+#qemu_guest_agent_enable="YES"
+#
+# For detailed logging add flags -v and -l to /etc/rc.conf
+#
+#qemu_guest_agent_flags="-d -v -l /var/log/qemu-ga.log"
+
+. /etc/rc.subr
+
+name=qemu_guest_agent
+rcvar=qemu_guest_agent_enable
+
+load_rc_config $name
+
+qemu_guest_agent_flags=${qemu_guest_agent_flags-"-d"}
+qemu_guest_agent_enable=${qemu_guest_agent_enable:-"NO"}
+
+qemu_guest_agent_bin=/usr/local/bin/qemu-ga
+command=${qemu_guest_agent_bin}
+pidfile="/var/run/qemu-ga.pid"
+
+run_rc_command "$1"
diff --git a/emulators/qemu-guest-agent/pkg-descr b/emulators/qemu-guest-agent/pkg-descr
new file mode 100644
index 000000000000..2ff691560721
--- /dev/null
+++ b/emulators/qemu-guest-agent/pkg-descr
@@ -0,0 +1,5 @@
+QEMU Guest Agent for FreeBSD
+
+Port homepage https://github.com/aborche/qemu-guest-agent
+
+WWW: http://wiki.qemu.org/Main_Page
diff --git a/emulators/qemu-guest-agent/pkg-message b/emulators/qemu-guest-agent/pkg-message
new file mode 100644
index 000000000000..aa56e6559686
--- /dev/null
+++ b/emulators/qemu-guest-agent/pkg-message
@@ -0,0 +1,17 @@
+[
+{ type: install
+ message: <<EOM
+=======================================================
+Modify your `/etc/rc.conf` by adding these settings
+
+qemu_guest_agent_enable="YES"
+qemu_guest_agent_flags="-d -v -l /var/log/qemu-ga.log"
+
+and run
+# service qemu-guest-agent start
+
+For detailed help use `qemu-ga -h`
+=======================================================
+EOM
+}
+]
diff --git a/emulators/qemu-guest-agent/pkg-message-11 b/emulators/qemu-guest-agent/pkg-message-11
new file mode 100644
index 000000000000..aa4cddb92062
--- /dev/null
+++ b/emulators/qemu-guest-agent/pkg-message-11
@@ -0,0 +1,24 @@
+[
+{ type: install
+ message: <<EOM
+=======================================================
+Modify your `/etc/rc.conf` by adding these settings
+
+qemu_guest_agent_enable="YES"
+qemu_guest_agent_flags="-d -v -l /var/log/qemu-ga.log"
+
+and run
+# service qemu-guest-agent start
+
+For FreeBSD less than 12
+------------------------
+virtio_console driver in FreeBSD 11 doesn't support aliasing virtio channels in devfs. Use direct path for control device. eq:
+qemu_guest_agent_flags="-d -v -l /var/log/qemu-ga.log -p /dev/ttyV0.2"
+
+For detailed help use `qemu-ga -h`
+
+Also read port homepage https://github.com/aborche/qemu-guest-agent
+=======================================================
+EOM
+}
+]
diff --git a/emulators/qemu-guest-agent/pkg-plist b/emulators/qemu-guest-agent/pkg-plist
new file mode 100644
index 000000000000..bdf1d5673a6a
--- /dev/null
+++ b/emulators/qemu-guest-agent/pkg-plist
@@ -0,0 +1 @@
+bin/qemu-ga