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