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