416 lines
12 KiB
Text
416 lines
12 KiB
Text
Adapted from https://github.com/aborche/qemu-guest-agent
|
|
|
|
Adds support for "guest-get-fsinfo" and "guest-get-vcpus"
|
|
|
|
Index: qga/commands-posix.c
|
|
--- qga/commands-posix.c.orig
|
|
+++ qga/commands-posix.c
|
|
@@ -56,6 +56,11 @@
|
|
#endif
|
|
#endif
|
|
|
|
+#ifdef __OpenBSD__
|
|
+#include <sys/sysctl.h>
|
|
+#include <sys/statvfs.h>
|
|
+#endif
|
|
+
|
|
static void ga_wait_child(pid_t pid, int *status, Error **errp)
|
|
{
|
|
pid_t rpid;
|
|
@@ -2743,7 +2748,7 @@ GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp
|
|
return head;
|
|
}
|
|
|
|
-#else /* defined(__linux__) */
|
|
+#elif defined(CONFIG_BSD)
|
|
|
|
void qmp_guest_suspend_disk(Error **errp)
|
|
{
|
|
@@ -2762,10 +2767,99 @@ void qmp_guest_suspend_hybrid(Error **errp)
|
|
|
|
GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
|
|
{
|
|
+ int64_t current;
|
|
+ GuestLogicalProcessorList *head, **tail;
|
|
+ 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
|
|
+
|
|
+ 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");
|
|
+ }
|
|
+ sc_max = NumCpu;
|
|
+
|
|
+ while (local_err == NULL && current < sc_max) {
|
|
+ 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;
|
|
+}
|
|
+
|
|
+int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
|
|
+{
|
|
error_setg(errp, QERR_UNSUPPORTED);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
|
|
+{
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
return NULL;
|
|
}
|
|
|
|
+GuestMemoryBlockResponseList *
|
|
+qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
|
|
+{
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
|
|
+{
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+#else /* defined(CONFIG_BSD) */
|
|
+
|
|
+void qmp_guest_suspend_disk(Error **errp)
|
|
+{
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
+}
|
|
+
|
|
+void qmp_guest_suspend_ram(Error **errp)
|
|
+{
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
+}
|
|
+
|
|
+void qmp_guest_suspend_hybrid(Error **errp)
|
|
+{
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
+}
|
|
+
|
|
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
|
|
+{
|
|
+ error_setg(errp, QERR_UNSUPPORTED);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
|
|
{
|
|
error_setg(errp, QERR_UNSUPPORTED);
|
|
@@ -3060,11 +3154,245 @@ GuestNetworkInterfaceList *qmp_guest_network_get_inter
|
|
|
|
#if !defined(CONFIG_FSFREEZE)
|
|
|
|
+#ifdef CONFIG_BSD
|
|
+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;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ g_free(line);
|
|
+
|
|
+ fclose(fp);
|
|
+}
|
|
+
|
|
+#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)
|
|
+{
|
|
+ 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 (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;
|
|
+ }
|
|
+
|
|
+#ifdef __OpenBSD__
|
|
+ add_type_fs_mount_list(&mounts, &local_err);
|
|
+ if (local_err) {
|
|
+ error_propagate(errp, local_err);
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ free_fs_mount_list(&mounts);
|
|
+ return ret;
|
|
+}
|
|
+#else
|
|
+GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
|
|
+{
|
|
error_setg(errp, QERR_UNSUPPORTED);
|
|
return NULL;
|
|
}
|
|
+#endif /* CONFIG_BSD */
|
|
|
|
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
|
|
{
|
|
@@ -3130,12 +3458,21 @@ GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
|
|
{
|
|
#if !defined(__linux__)
|
|
{
|
|
+#ifdef CONFIG_BSD
|
|
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};
|
|
+#else
|
|
+ const char *list[] = {
|
|
+ "guest-suspend-disk", "guest-suspend-ram",
|
|
"guest-suspend-hybrid", "guest-get-vcpus", "guest-set-vcpus",
|
|
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
|
"guest-get-memory-block-size", "guest-get-memory-block-info",
|
|
NULL};
|
|
+#endif /* CONFIG_BSD */
|
|
char **p = (char **)list;
|
|
|
|
while (*p) {
|
|
@@ -3151,11 +3488,19 @@ GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
|
|
|
|
#if !defined(CONFIG_FSFREEZE)
|
|
{
|
|
+#ifdef CONFIG_BSD
|
|
const char *list[] = {
|
|
+ "guest-fsfreeze-status",
|
|
+ "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
|
|
+ "guest-fsfreeze-thaw",
|
|
+ "guest-get-disks", NULL};
|
|
+#else
|
|
+ const char *list[] = {
|
|
"guest-get-fsinfo", "guest-fsfreeze-status",
|
|
"guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
|
|
"guest-fsfreeze-thaw", "guest-get-fsinfo",
|
|
"guest-get-disks", NULL};
|
|
+#endif /* CONFIG_BSD */
|
|
char **p = (char **)list;
|
|
|
|
while (*p) {
|