]>
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 | 23 | #include <net/if_dl.h> |
28236ad8 BS |
24 | #if defined(__NetBSD__) || defined(__OpenBSD__) |
25 | #include <net/if_arp.h> | |
26 | #include <netinet/if_ether.h> | |
27 | #else | |
ffb01cc5 | 28 | #include <net/ethernet.h> |
28236ad8 | 29 | #endif |
bad0001e AI |
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 */ | |
a1241094 AI |
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 | { | |
ffb01cc5 AI |
189 | struct sockaddr_dl *sdp; |
190 | ||
a1241094 | 191 | *obtained = false; |
ffb01cc5 AI |
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 | ||
a1241094 AI |
203 | return true; |
204 | } | |
205 | #endif /* HAVE_GETIFADDRS */ |