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