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