From: Brad Smith Subject: UPDATE: QEMU To: ports@openbsd.org Date: Sun, 20 Sep 2026 21:36:50 -0400 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 ++ #include ++ int main(void) { ++ char buf[PATH_MAX]; ++ getexecpath(buf, sizeof(buf)); ++ }''')) ++ + config_host_data.set('CONFIG_USBFS', have_linux_user and cc.compiles(''' + #include + +@@ -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 #include -@@ -27,6 +26,8 @@ + #include + #include + #include ++#include + #if defined(__NetBSD__) || defined(__OpenBSD__) + #include + #include +@@ -27,12 +27,20 @@ #include #endif #include -+#include -+#include ++#ifdef __FreeBSD__ ++#include ++#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 ++#include + #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];