 28236ad8d1
			
		
	
	
		28236ad8d1
		
	
	
	
	
		
			
			qga: Add initial OpenBSD and NetBSD support Signed-off-by: Brad Smith <brad@comstyle.com> Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
		
			
				
	
	
		
			206 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * QEMU Guest Agent BSD-specific command implementations
 | |
|  *
 | |
|  * Copyright (c) Virtuozzo International GmbH.
 | |
|  *
 | |
|  * Authors:
 | |
|  *  Alexander Ivanov  <alexander.ivanov@virtuozzo.com>
 | |
|  *
 | |
|  * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | |
|  * See the COPYING file in the top-level directory.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qga-qapi-commands.h"
 | |
| #include "qapi/qmp/qerror.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>
 | |
| #if defined(__NetBSD__) || defined(__OpenBSD__)
 | |
| #include <net/if_arp.h>
 | |
| #include <netinet/if_ether.h>
 | |
| #else
 | |
| #include <net/ethernet.h>
 | |
| #endif
 | |
| #include <paths.h>
 | |
| 
 | |
| #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
 | |
| bool build_fs_mount_list(FsMountList *mounts, Error **errp)
 | |
| {
 | |
|     FsMount *mount;
 | |
|     struct statfs *mntbuf, *mntp;
 | |
|     struct stat statbuf;
 | |
|     int i, count, ret;
 | |
| 
 | |
|     count = getmntinfo(&mntbuf, MNT_NOWAIT);
 | |
|     if (count == 0) {
 | |
|         error_setg_errno(errp, errno, "getmntinfo failed");
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < count; i++) {
 | |
|         mntp = &mntbuf[i];
 | |
|         ret = stat(mntp->f_mntonname, &statbuf);
 | |
|         if (ret != 0) {
 | |
|             error_setg_errno(errp, errno, "stat failed on %s",
 | |
|                              mntp->f_mntonname);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         mount = g_new0(FsMount, 1);
 | |
| 
 | |
|         mount->dirname = g_strdup(mntp->f_mntonname);
 | |
|         mount->devtype = g_strdup(mntp->f_fstypename);
 | |
|         mount->devmajor = major(mount->dev);
 | |
|         mount->devminor = minor(mount->dev);
 | |
|         mount->fsid = mntp->f_fsid;
 | |
|         mount->dev = statbuf.st_dev;
 | |
| 
 | |
|         QTAILQ_INSERT_TAIL(mounts, mount, next);
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| #endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */
 | |
| 
 | |
| #if defined(CONFIG_FSFREEZE)
 | |
| static int ufssuspend_fd = -1;
 | |
| static int ufssuspend_cnt;
 | |
| 
 | |
| int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints,
 | |
|                                           strList *mountpoints,
 | |
|                                           FsMountList mounts,
 | |
|                                           Error **errp)
 | |
| {
 | |
|     int ret;
 | |
|     strList *list;
 | |
|     struct FsMount *mount;
 | |
| 
 | |
|     if (ufssuspend_fd != -1) {
 | |
|         error_setg(errp, "filesystems have already frozen");
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     ufssuspend_cnt = 0;
 | |
|     ufssuspend_fd = qemu_open(_PATH_UFSSUSPEND, O_RDWR, errp);
 | |
|     if (ufssuspend_fd == -1) {
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     QTAILQ_FOREACH_REVERSE(mount, &mounts, next) {
 | |
|         /*
 | |
|          * To issue fsfreeze in the reverse order of mounts, check if the
 | |
|          * mount is listed in the list here
 | |
|          */
 | |
|         if (has_mountpoints) {
 | |
|             for (list = mountpoints; list; list = list->next) {
 | |
|                 if (g_str_equal(list->value, mount->dirname)) {
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             if (!list) {
 | |
|                 continue;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Only UFS supports suspend */
 | |
|         if (!g_str_equal(mount->devtype, "ufs")) {
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         ret = ioctl(ufssuspend_fd, UFSSUSPEND, &mount->fsid);
 | |
|         if (ret == -1) {
 | |
|             /*
 | |
|              * ioctl returns EBUSY for all the FS except the first one
 | |
|              * that was suspended
 | |
|              */
 | |
|             if (errno == EBUSY) {
 | |
|                 continue;
 | |
|             }
 | |
|             error_setg_errno(errp, errno, "failed to freeze %s",
 | |
|                              mount->dirname);
 | |
|             goto error;
 | |
|         }
 | |
|         ufssuspend_cnt++;
 | |
|     }
 | |
|     return ufssuspend_cnt;
 | |
| error:
 | |
|     close(ufssuspend_fd);
 | |
|     ufssuspend_fd = -1;
 | |
|     return -1;
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * We don't need to call UFSRESUME ioctl because all the frozen FS
 | |
|  * are thawed on /dev/ufssuspend closing.
 | |
|  */
 | |
| int qmp_guest_fsfreeze_do_thaw(Error **errp)
 | |
| {
 | |
|     int ret = ufssuspend_cnt;
 | |
|     ufssuspend_cnt = 0;
 | |
|     if (ufssuspend_fd != -1) {
 | |
|         close(ufssuspend_fd);
 | |
|         ufssuspend_fd = -1;
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
 | |
| {
 | |
|     error_setg(errp, QERR_UNSUPPORTED);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
 | |
| {
 | |
|     error_setg(errp, QERR_UNSUPPORTED);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
 | |
| {
 | |
|     error_setg(errp, QERR_UNSUPPORTED);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
 | |
| {
 | |
|     error_setg(errp, QERR_UNSUPPORTED);
 | |
|     return NULL;
 | |
| }
 | |
| #endif /* CONFIG_FSFREEZE */
 | |
| 
 | |
| #ifdef HAVE_GETIFADDRS
 | |
| /*
 | |
|  * Fill "buf" with MAC address by ifaddrs. Pointer buf must point to a
 | |
|  * buffer with ETHER_ADDR_LEN length at least.
 | |
|  *
 | |
|  * Returns false in case of an error, otherwise true. "obtained" arguument
 | |
|  * is true if a MAC address was obtained successful, otherwise false.
 | |
|  */
 | |
| bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned char *buf,
 | |
|                        bool *obtained, Error **errp)
 | |
| {
 | |
|     struct sockaddr_dl *sdp;
 | |
| 
 | |
|     *obtained = false;
 | |
| 
 | |
|     if (ifa->ifa_addr->sa_family != AF_LINK) {
 | |
|         /* We can get HW address only for AF_LINK family. */
 | |
|         g_debug("failed to get MAC address of %s", ifa->ifa_name);
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     sdp = (struct sockaddr_dl *)ifa->ifa_addr;
 | |
|     memcpy(buf, sdp->sdl_data + sdp->sdl_nlen, ETHER_ADDR_LEN);
 | |
|     *obtained = true;
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| #endif /* HAVE_GETIFADDRS */
 |