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