This integrates the getexecpath() diff I had as well as
some further fixes for QGA.
Replaces the horrible code for FS info retrieval with a
combination of reuse of what was there for FreeBSD, a
recent FreeBSD commit for guest-get-fsinfo and a diff to
tweak the code to build on NetBSD and OpenBSD.
Rewritten qmp_guest_get_vcpus() function and uses
sysconf(_SC_NPROCESSORS_ONLN).
Index: Makefile
===================================================================
RCS file: /cvs/ports/emulators/qemu/Makefile,v
retrieving revision 1.266
diff -u -p -u -p -r1.266 Makefile
--- Makefile 3 Sep 2026 08:58:14 -0000 1.266
+++ Makefile 21 Sep 2026 01:05:18 -0000
@@ -8,6 +8,7 @@ COMMENT-ga= QEMU guest agent
VERSION= 11.1.1
DISTNAME= qemu-${VERSION}
+REVISION= 0
CATEGORIES= emulators
SITES= https://download.qemu.org/
EXTRACT_SUFX= .tar.xz
Index: patches/patch-meson_build
===================================================================
RCS file: /cvs/ports/emulators/qemu/patches/patch-meson_build,v
retrieving revision 1.23
diff -u -p -u -p -r1.23 patch-meson_build
--- patches/patch-meson_build 3 Sep 2026 08:58:14 -0000 1.23
+++ patches/patch-meson_build 21 Sep 2026 01:05:18 -0000
@@ -1,3 +1,5 @@
+- util/cutils: Use getexecpath() on OpenBSD for qemu_init_exec_dir()
+
- localstatedir does not belong under prefix
- remove hardcoding of optimization
@@ -13,7 +15,22 @@ Index: meson.build
config_host_data.set_quoted('CONFIG_QEMU_MODDIR', get_option('prefix') /
qemu_moddir)
config_host_data.set_quoted('CONFIG_SYSCONFDIR', get_option('prefix') /
get_option('sysconfdir'))
-@@ -4753,9 +4753,6 @@ if have_rust
+@@ -3030,6 +3030,14 @@ config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(o
+ return hwcap;
+ }'''))
+
++config_host_data.set('CONFIG_GETEXECPATH', cc.links(osdep_prefix + '''
++ #include <limits.h>
++ #include <unistd.h>
++ int main(void) {
++ char buf[PATH_MAX];
++ getexecpath(buf, sizeof(buf));
++ }'''))
++
+ config_host_data.set('CONFIG_USBFS', have_linux_user and cc.compiles('''
+ #include <linux/usbdevice_fs.h>
+
+@@ -4753,9 +4761,6 @@ if have_rust
summary_info += {'bindgen version': bindgen.version()}
endif
option_cflags = (get_option('debug') ? ['-g'] : [])
Index: patches/patch-qga_commands-bsd_c
===================================================================
RCS file: /cvs/ports/emulators/qemu/patches/patch-qga_commands-bsd_c,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 patch-qga_commands-bsd_c
--- patches/patch-qga_commands-bsd_c 8 Jan 2025 15:19:11 -0000 1.4
+++ patches/patch-qga_commands-bsd_c 21 Sep 2026 01:05:18 -0000
@@ -1,31 +1,71 @@
-Adapted from https://github.com/aborche/qemu-guest-agent
-
-Adds support for "guest-get-fsinfo" and "guest-get-vcpus"
+- qga: implement 'guest-get-fsinfo' for FreeBSD
+ 2a454b5391ad4241c8d59d8325d8bacac9af7a8c
+- qga: implement 'guest-get-fsinfo' for NetBSD and OpenBSD
+- qga: implement 'guest-get-vcpus' for the BSDs
Index: qga/commands-bsd.c
--- qga/commands-bsd.c.orig
+++ qga/commands-bsd.c
-@@ -11,9 +11,8 @@
- */
-
+@@ -13,13 +13,13 @@
#include "qemu/osdep.h"
--#include "qga-qapi-commands.h"
+ #include "qga-qapi-commands.h"
#include "qapi/error.h"
-#include "qemu/queue.h"
-+#include "qga-qapi-commands.h"
#include "commands-common.h"
#include <sys/ioctl.h>
#include <sys/param.h>
-@@ -27,6 +26,8 @@
+ #include <sys/ucred.h>
+ #include <sys/mount.h>
+ #include <net/if_dl.h>
++#include <sys/statvfs.h>
+ #if defined(__NetBSD__) || defined(__OpenBSD__)
+ #include <net/if_arp.h>
+ #include <netinet/if_ether.h>
+@@ -27,12 +27,20 @@
#include <net/ethernet.h>
#endif
#include <paths.h>
-+#include <sys/sysctl.h>
-+#include <sys/statvfs.h>
++#ifdef __FreeBSD__
++#include <ufs/ffs/fs.h>
++#endif
- #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
+-#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
++#ifdef __NetBSD__
++typedef struct statvfs bsd_fsinfo_t;
++#else
++typedef struct statfs bsd_fsinfo_t;
++#endif
++
bool build_fs_mount_list(FsMountList *mounts, Error **errp)
-@@ -178,3 +179,278 @@ bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned c
+ {
+ FsMount *mount;
+- struct statfs *mntbuf, *mntp;
++ bsd_fsinfo_t *mntbuf, *mntp;
+ struct stat statbuf;
+ int i, count, ret;
+
+@@ -55,16 +63,18 @@ bool build_fs_mount_list(FsMountList *mounts, Error **
+
+ mount->dirname = g_strdup(mntp->f_mntonname);
+ mount->devtype = g_strdup(mntp->f_fstypename);
++ mount->fromname = g_strdup(mntp->f_mntfromname);
++ mount->dev = statbuf.st_dev;
+ mount->devmajor = major(mount->dev);
+ mount->devminor = minor(mount->dev);
++#ifdef CONFIG_FSFREEZE
+ mount->fsid = mntp->f_fsid;
+- mount->dev = statbuf.st_dev;
++#endif
+
+ QTAILQ_INSERT_TAIL(mounts, mount, next);
+ }
+ return true;
+ }
+-#endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */
+
+ #if defined(CONFIG_FSFREEZE)
+ static int ufssuspend_fd = -1;
+@@ -178,3 +188,79 @@ bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned c
return true;
}
#endif /* HAVE_GETIFADDRS */
@@ -33,220 +73,41 @@ Index: qga/commands-bsd.c
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+{
+ GuestLogicalProcessorList *head, **tail;
-+ int64_t current;
-+ long sc_max;
-+ Error *local_err = NULL;
-+ int Query[2];
-+ int NumCpu = 0;
-+ size_t Length = sizeof(NumCpu);
-+
-+ Query[0] = CTL_HW;
-+#ifdef HW_NCPUONLINE
-+ Query[1] = HW_NCPUONLINE;
-+#else
-+ Query[1] = HW_NCPU;
-+#endif
++ long ncpu;
++ int64_t id;
+
-+ current = 0;
+ head = NULL;
+ tail = &head;
-+ if (sysctl(Query, 2, &NumCpu, &Length, NULL, 0) == -1) {
-+ error_setg(errp, "sysctl get CTL_HW.HW_NCPU failed");
++
++ ncpu = sysconf(_SC_NPROCESSORS_ONLN);
++ if (ncpu < 1) {
++ error_setg(errp, "failed to query number of online CPUs");
++ return NULL;
+ }
-+ sc_max = NumCpu;
+
-+ while (local_err == NULL && current < sc_max) {
++ for (id = 0; id < ncpu; id++) {
+ GuestLogicalProcessor *vcpu;
-+ int64_t id = current++;
++
+ vcpu = g_malloc0(sizeof *vcpu);
+ vcpu->logical_id = id;
-+ vcpu->has_can_offline = false; /* lolspeak ftw */
+ vcpu->online = true;
-+ vcpu->can_offline = false;
-+ QAPI_LIST_APPEND(tail, vcpu);
-+ }
-+
-+ 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;
-+}
++ vcpu->has_can_offline = true; /* can_offline stays false */
+
-+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);
-+ }
-+}
-+
-+static void build_fs_mount_list(FsMountList *mounts, Error **errp)
-+{
-+ FsMount *mount;
-+#ifdef __OpenBSD__
-+ char const *dfcmd = "/bin/df";
-+#else // defined(__OpenBSD__)
-+ char const *dfcmd = "/bin/df -hT";
-+#endif // defined(__OpenBSD__)
-+
-+ FILE *fp;
-+ char *line = NULL;
-+ size_t n;
-+ int ret;
-+ char dev_name[128], size[12], used[12], free[12], load[10], mounted[128];
-+#ifndef __OpenBSD__
-+ char fstype[12] = "";
-+#endif // !defined(__OpenBSD__)
-+
-+ if ((fp = popen(dfcmd, "r")) == NULL) {
-+ g_debug("Cannot open '%s'!!\n", dfcmd);
-+ error_setg_errno(errp, errno,
-+ "failed to create child process for command: %s",
-+ dfcmd);
-+ return;
-+ }
-+
-+ while (getline(&line, &n, fp) != -1) {
-+ //g_debug("line '%s'", line);
-+#ifdef __OpenBSD__
-+ ret = sscanf(line, "%127s%11s%11s%11s%9s%127s",
-+ dev_name, size, used, free, load, mounted);
-+#else // defined(__OpenBSD__)
-+ ret = sscanf(line, "%127s%11s%11s%11s%11s%9s%127s",
-+ dev_name, fstype, size, used, free, load, mounted);
-+ //g_debug("ret %d, dev_name '%s', fstype '%s', size '%s', used '%s',
free '%s', load '%s', mounted '%s'",
-+ // ret, dev_name, fstype, size, used, free, load, mounted);
-+#endif // defined(__OpenBSD__)
-+ if (g_str_equal(dev_name, "Filesystem")
-+#ifndef __OpenBSD__
-+ ||g_str_equal(fstype,"devfs")
-+ ||g_str_equal(fstype,"procfs")
-+ ||g_str_equal(fstype,"fdescfs")
-+#endif // !defined(__OpenBSD__)
-+ ) {
-+ continue;
-+ }
-+
-+#ifdef __OpenBSD__
-+ if (ret < 6) {
-+#else // defined(__OpenBSD__)
-+ if (ret < 7) {
-+#endif // defined(__OpenBSD__)
-+ continue;
-+ }
-+
-+ mount = g_new0(FsMount, 1);
-+ mount->dirname = g_strdup(dev_name);
-+#ifndef __OpenBSD__
-+ mount->devtype = g_strdup(fstype);
-+#endif // defined(__OpenBSD__)
-+ 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);
-+ }
-+ g_free(line);
-+
-+ fclose(fp);
-+}
-+
-+#ifdef __OpenBSD__
-+static void add_type_fs_mount_list(FsMountList *mounts, Error **errp)
-+{
-+ FILE *fp;
-+ char const *mountcmd = "/sbin/mount";
-+ char *line = NULL;
-+ size_t n;
-+ int ret;
-+ char mnt_fsname[128], mnt_dir[128], mnt_type[32], mnt_opts[128];
-+ struct FsMount *mount;
-+
-+ // get mounts from mount command
-+ if ((fp = popen(mountcmd, "r")) == NULL) {
-+ g_debug("Cannot open '%s'!!\n", mountcmd);
-+ error_setg_errno(errp, errno, "failed to create child process for
command: %s", mountcmd);
-+ return;
-+ }
-+
-+ // loop through mounts from mount command
-+ while (getline(&line, &n, fp) != -1) {
-+ //g_debug("line '%s'", line);
-+
-+ ret = sscanf(line, "%127s on %127s type %31s (%127s)",
-+ mnt_fsname, mnt_dir, mnt_type, mnt_opts);
-+ //g_debug("ret %d, fsname '%s', dir '%s', type '%s', opts '%s'",
-+ // ret, mnt_fsname, mnt_dir, mnt_type, mnt_opts);
-+
-+ if (4 != ret ||
-+ '/' != mnt_fsname[0] ||
-+ '/' != mnt_dir[0] ||
-+ g_str_equal("smbfs", mnt_type) ||
-+ g_str_equal("cifs", mnt_type)) {
-+ continue;
-+ }
-+
-+ // find mount in supplied mounts list and update device type
-+ QTAILQ_FOREACH(mount, mounts, next) {
-+ if (NULL == mount->devtype && g_str_equal(mount->dirname,
mnt_fsname)) {
-+ mount->devtype = g_strdup(mnt_type);
-+ break;
-+ }
-+ }
++ QAPI_LIST_APPEND(tail, vcpu);
+ }
-+ g_free(line);
+
-+ fclose(fp);
++ return head;
+}
-+#endif // defined(__OpenBSD__)
+
-+/* Return a list of the disk device(s)' info which @mount lies on */
-+static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
-+ Error **errp)
++static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount)
+{
-+ GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
++ GuestFilesystemInfo *fs = g_new0(GuestFilesystemInfo, 1);
+ struct statvfs buf;
+ unsigned long used, nonroot_total, fr_size;
+
-+ fs->name = g_strdup(mount->dirname);
-+ fs->mountpoint = g_strdup(mount->mntpoint);
++ fs->mountpoint = g_strdup(mount->dirname);
+ fs->type = g_strdup(mount->devtype);
++ fs->name = g_path_get_basename(mount->fromname);
+
+ if (statvfs(fs->mountpoint, &buf) == 0) {
+ fr_size = buf.f_frsize;
@@ -254,8 +115,10 @@ Index: qga/commands-bsd.c
+ nonroot_total = used + buf.f_bavail;
+ fs->used_bytes = used * fr_size;
+ fs->total_bytes = nonroot_total * fr_size;
++ fs->total_bytes_privileged = buf.f_blocks * fr_size;
+
+ fs->has_total_bytes = true;
++ fs->has_total_bytes_privileged = true;
+ fs->has_used_bytes = true;
+ }
+
@@ -266,39 +129,17 @@ Index: qga/commands-bsd.c
+{
+ FsMountList mounts;
+ struct FsMount *mount;
-+ GuestFilesystemInfoList *new, *ret = NULL;
-+ Error *local_err = NULL;
++ GuestFilesystemInfoList *ret = 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;
-+ }
-+
-+#ifdef __OpenBSD__
-+ add_type_fs_mount_list(&mounts, &local_err);
-+ if (local_err) {
-+ error_propagate(errp, local_err);
++ if (!build_fs_mount_list(&mounts, errp)) {
+ return NULL;
+ }
-+#endif // defined(__OpenBSD__)
+
+ 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;
-+ }
++ g_debug("Building guest fsinfo for '%s'", mount->dirname);
++
++ QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount));
+ }
+
+ free_fs_mount_list(&mounts);
Index: patches/patch-qga_commands-common_h
===================================================================
RCS file: patches/patch-qga_commands-common_h
diff -N patches/patch-qga_commands-common_h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-qga_commands-common_h 21 Sep 2026 01:05:18 -0000
@@ -0,0 +1,41 @@
+- qga: implement 'guest-get-fsinfo' for FreeBSD
+ 2a454b5391ad4241c8d59d8325d8bacac9af7a8c
+- qga: implement 'guest-get-fsinfo' for NetBSD and OpenBSD
+
+Index: qga/commands-common.h
+--- qga/commands-common.h.orig
++++ qga/commands-common.h
+@@ -18,18 +18,21 @@
+ #endif /* __linux__ */
+
+ #ifdef __FreeBSD__
+-#include <ufs/ffs/fs.h>
++#include <sys/mount.h>
+ #endif /* __FreeBSD__ */
+
+-#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
++#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) || defined(CONFIG_BSD)
+ typedef struct FsMount {
+ char *dirname;
+ char *devtype;
+ unsigned int devmajor, devminor;
+ #if defined(__FreeBSD__)
+- dev_t dev;
+ fsid_t fsid;
+ #endif
++#ifdef CONFIG_BSD
++ dev_t dev;
++ char *fromname;
++#endif
+ QTAILQ_ENTRY(FsMount) next;
+ } FsMount;
+
+@@ -37,7 +40,7 @@ typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList;
+
+ bool build_fs_mount_list(FsMountList *mounts, Error **errp);
+ void free_fs_mount_list(FsMountList *mounts);
+-#endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */
++#endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM || CONFIG_BSD */
+
+ #if defined(CONFIG_FSFREEZE)
+ int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints,
Index: patches/patch-qga_commands-posix_c
===================================================================
RCS file: patches/patch-qga_commands-posix_c
diff -N patches/patch-qga_commands-posix_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-qga_commands-posix_c 21 Sep 2026 01:05:18 -0000
@@ -0,0 +1,26 @@
+- qga: implement 'guest-get-fsinfo' for FreeBSD
+ 2a454b5391ad4241c8d59d8325d8bacac9af7a8c
+- qga: implement 'guest-get-fsinfo' for NetBSD and OpenBSD
+
+Index: qga/commands-posix.c
+--- qga/commands-posix.c.orig
++++ qga/commands-posix.c
+@@ -718,7 +718,7 @@ void qmp_guest_file_flush(int64_t handle, Error **errp
+ }
+ }
+
+-#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
++#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) || defined(CONFIG_BSD)
+ void free_fs_mount_list(FsMountList *mounts)
+ {
+ FsMount *mount, *temp;
+@@ -731,6 +731,9 @@ void free_fs_mount_list(FsMountList *mounts)
+ QTAILQ_REMOVE(mounts, mount, next);
+ g_free(mount->dirname);
+ g_free(mount->devtype);
++#ifdef CONFIG_BSD
++ g_free(mount->fromname);
++#endif
+ g_free(mount);
+ }
+ }
Index: patches/patch-qga_qapi-schema_json
===================================================================
RCS file: /cvs/ports/emulators/qemu/patches/patch-qga_qapi-schema_json,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 patch-qga_qapi-schema_json
--- patches/patch-qga_qapi-schema_json 10 Feb 2026 10:46:00 -0000 1.4
+++ patches/patch-qga_qapi-schema_json 21 Sep 2026 01:05:18 -0000
@@ -1,6 +1,7 @@
-Adapted from https://github.com/aborche/qemu-guest-agent
-
-Adds support for "guest-get-fsinfo" and "guest-get-vcpus"
+- qga: implement 'guest-get-fsinfo' for FreeBSD
+ 2a454b5391ad4241c8d59d8325d8bacac9af7a8c
+- qga: implement 'guest-get-fsinfo' for NetBSD and OpenBSD
+- qga: implement 'guest-get-vcpus' for the BSDs
Index: qga/qapi-schema.json
--- qga/qapi-schema.json.orig
Index: patches/patch-util_cutils_c
===================================================================
RCS file: patches/patch-util_cutils_c
diff -N patches/patch-util_cutils_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-util_cutils_c 21 Sep 2026 01:05:18 -0000
@@ -0,0 +1,18 @@
+- util/cutils: Use getexecpath() on OpenBSD for qemu_init_exec_dir()
+
+Index: util/cutils.c
+--- util/cutils.c.orig
++++ util/cutils.c
+@@ -1091,6 +1091,12 @@ void qemu_init_exec_dir(const char *argv0)
+ p = buf;
+ }
+ }
++#elif defined(__OpenBSD__) && defined(CONFIG_GETEXECPATH)
++ {
++ if (getexecpath(buf, sizeof(buf)) == 0) {
++ p = buf;
++ }
++ }
+ #elif defined(__APPLE__)
+ {
+ char fpath[PATH_MAX];