- 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
@@ -13,13 +13,13 @@
 #include "qemu/osdep.h"
 #include "qga-qapi-commands.h"
 #include "qapi/error.h"
-#include "qemu/queue.h"
 #include "commands-common.h"
 #include <sys/ioctl.h>
 #include <sys/param.h>
 #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>
+#ifdef __FreeBSD__
+#include <ufs/ffs/fs.h>
+#endif
 
-#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)
 {
     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 */
+
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+{
+    GuestLogicalProcessorList *head, **tail;
+    long ncpu;
+    int64_t id;
+
+    head = NULL;
+    tail = &head;
+
+    ncpu = sysconf(_SC_NPROCESSORS_ONLN);
+    if (ncpu < 1) {
+        error_setg(errp, "failed to query number of online CPUs");
+        return NULL;
+    }
+
+    for (id = 0; id < ncpu; id++) {
+        GuestLogicalProcessor *vcpu;
+
+        vcpu = g_malloc0(sizeof *vcpu);
+        vcpu->logical_id = id;
+        vcpu->online = true;
+        vcpu->has_can_offline = true;  /* can_offline stays false */
+
+        QAPI_LIST_APPEND(tail, vcpu);
+    }
+
+    return head;
+}
+
+static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount)
+{
+    GuestFilesystemInfo *fs = g_new0(GuestFilesystemInfo, 1);
+    struct statvfs buf;
+    unsigned long used, nonroot_total, fr_size;
+
+    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;
+        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->total_bytes_privileged = buf.f_blocks * fr_size;
+
+        fs->has_total_bytes = true;
+        fs->has_total_bytes_privileged = true;
+        fs->has_used_bytes = true;
+    }
+
+    return fs;
+}
+
+GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
+{
+    FsMountList mounts;
+    struct FsMount *mount;
+    GuestFilesystemInfoList *ret = NULL;
+
+    QTAILQ_INIT(&mounts);
+    if (!build_fs_mount_list(&mounts, errp)) {
+        return NULL;
+    }
+
+    QTAILQ_FOREACH(mount, &mounts, next) {
+        g_debug("Building guest fsinfo for '%s'", mount->dirname);
+
+        QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount));
+    }
+
+    free_fs_mount_list(&mounts);
+    return ret;
+}
