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];

Reply via email to