1 /* 2 * QEMU Guest Agent BSD-specific command implementations 3 * 4 * Copyright (c) Virtuozzo International GmbH. 5 * 6 * Authors: 7 * Alexander Ivanov <alexander.ivanov@virtuozzo.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qga-qapi-commands.h" 15 #include "qapi/error.h" 16 #include "qemu/queue.h" 17 #include "commands-common.h" 18 #include <sys/ioctl.h> 19 #include <sys/param.h> 20 #include <sys/ucred.h> 21 #include <sys/mount.h> 22 #include <net/if_dl.h> 23 #if defined(__NetBSD__) || defined(__OpenBSD__) 24 #include <net/if_arp.h> 25 #include <netinet/if_ether.h> 26 #else 27 #include <net/ethernet.h> 28 #endif 29 #include <paths.h> 30 31 #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) 32 bool build_fs_mount_list(FsMountList *mounts, Error **errp) 33 { 34 FsMount *mount; 35 struct statfs *mntbuf, *mntp; 36 struct stat statbuf; 37 int i, count, ret; 38 39 count = getmntinfo(&mntbuf, MNT_NOWAIT); 40 if (count == 0) { 41 error_setg_errno(errp, errno, "getmntinfo failed"); 42 return false; 43 } 44 45 for (i = 0; i < count; i++) { 46 mntp = &mntbuf[i]; 47 ret = stat(mntp->f_mntonname, &statbuf); 48 if (ret != 0) { 49 error_setg_errno(errp, errno, "stat failed on %s", 50 mntp->f_mntonname); 51 return false; 52 } 53 54 mount = g_new0(FsMount, 1); 55 56 mount->dirname = g_strdup(mntp->f_mntonname); 57 mount->devtype = g_strdup(mntp->f_fstypename); 58 mount->devmajor = major(mount->dev); 59 mount->devminor = minor(mount->dev); 60 mount->fsid = mntp->f_fsid; 61 mount->dev = statbuf.st_dev; 62 63 QTAILQ_INSERT_TAIL(mounts, mount, next); 64 } 65 return true; 66 } 67 #endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */ 68 69 #if defined(CONFIG_FSFREEZE) 70 static int ufssuspend_fd = -1; 71 static int ufssuspend_cnt; 72 73 int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints, 74 strList *mountpoints, 75 FsMountList mounts, 76 Error **errp) 77 { 78 int ret; 79 strList *list; 80 struct FsMount *mount; 81 82 if (ufssuspend_fd != -1) { 83 error_setg(errp, "filesystems have already frozen"); 84 return -1; 85 } 86 87 ufssuspend_cnt = 0; 88 ufssuspend_fd = qemu_open(_PATH_UFSSUSPEND, O_RDWR, errp); 89 if (ufssuspend_fd == -1) { 90 return -1; 91 } 92 93 QTAILQ_FOREACH_REVERSE(mount, &mounts, next) { 94 /* 95 * To issue fsfreeze in the reverse order of mounts, check if the 96 * mount is listed in the list here 97 */ 98 if (has_mountpoints) { 99 for (list = mountpoints; list; list = list->next) { 100 if (g_str_equal(list->value, mount->dirname)) { 101 break; 102 } 103 } 104 if (!list) { 105 continue; 106 } 107 } 108 109 /* Only UFS supports suspend */ 110 if (!g_str_equal(mount->devtype, "ufs")) { 111 continue; 112 } 113 114 ret = ioctl(ufssuspend_fd, UFSSUSPEND, &mount->fsid); 115 if (ret == -1) { 116 /* 117 * ioctl returns EBUSY for all the FS except the first one 118 * that was suspended 119 */ 120 if (errno == EBUSY) { 121 continue; 122 } 123 error_setg_errno(errp, errno, "failed to freeze %s", 124 mount->dirname); 125 goto error; 126 } 127 ufssuspend_cnt++; 128 } 129 return ufssuspend_cnt; 130 error: 131 close(ufssuspend_fd); 132 ufssuspend_fd = -1; 133 return -1; 134 135 } 136 137 /* 138 * We don't need to call UFSRESUME ioctl because all the frozen FS 139 * are thawed on /dev/ufssuspend closing. 140 */ 141 int qmp_guest_fsfreeze_do_thaw(Error **errp) 142 { 143 int ret = ufssuspend_cnt; 144 ufssuspend_cnt = 0; 145 if (ufssuspend_fd != -1) { 146 close(ufssuspend_fd); 147 ufssuspend_fd = -1; 148 } 149 return ret; 150 } 151 #endif /* CONFIG_FSFREEZE */ 152 153 #ifdef HAVE_GETIFADDRS 154 /* 155 * Fill "buf" with MAC address by ifaddrs. Pointer buf must point to a 156 * buffer with ETHER_ADDR_LEN length at least. 157 * 158 * Returns false in case of an error, otherwise true. "obtained" arguument 159 * is true if a MAC address was obtained successful, otherwise false. 160 */ 161 bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned char *buf, 162 bool *obtained, Error **errp) 163 { 164 struct sockaddr_dl *sdp; 165 166 *obtained = false; 167 168 if (ifa->ifa_addr->sa_family != AF_LINK) { 169 /* We can get HW address only for AF_LINK family. */ 170 g_debug("failed to get MAC address of %s", ifa->ifa_name); 171 return true; 172 } 173 174 sdp = (struct sockaddr_dl *)ifa->ifa_addr; 175 memcpy(buf, sdp->sdl_data + sdp->sdl_nlen, ETHER_ADDR_LEN); 176 *obtained = true; 177 178 return true; 179 } 180 #endif /* HAVE_GETIFADDRS */ 181