root / qga / commands-posix.c @ eab5fd59
History | View | Annotate | Download (26.1 kB)
1 | e3d4d252 | Michael Roth | /*
|
---|---|---|---|
2 | 42074a9d | Michael Roth | * QEMU Guest Agent POSIX-specific command implementations
|
3 | e3d4d252 | Michael Roth | *
|
4 | e3d4d252 | Michael Roth | * Copyright IBM Corp. 2011
|
5 | e3d4d252 | Michael Roth | *
|
6 | e3d4d252 | Michael Roth | * Authors:
|
7 | e3d4d252 | Michael Roth | * Michael Roth <mdroth@linux.vnet.ibm.com>
|
8 | 3424fc9f | Michal Privoznik | * Michal Privoznik <mprivozn@redhat.com>
|
9 | e3d4d252 | Michael Roth | *
|
10 | e3d4d252 | Michael Roth | * This work is licensed under the terms of the GNU GPL, version 2 or later.
|
11 | e3d4d252 | Michael Roth | * See the COPYING file in the top-level directory.
|
12 | e3d4d252 | Michael Roth | */
|
13 | e3d4d252 | Michael Roth | |
14 | e3d4d252 | Michael Roth | #include <glib.h> |
15 | e72c3f2e | Michael Roth | #include <sys/types.h> |
16 | e72c3f2e | Michael Roth | #include <sys/ioctl.h> |
17 | 2c02cbf6 | Luiz Capitulino | #include <sys/wait.h> |
18 | e72c3f2e | Michael Roth | #include "qga/guest-agent-core.h" |
19 | e72c3f2e | Michael Roth | #include "qga-qmp-commands.h" |
20 | e72c3f2e | Michael Roth | #include "qerror.h" |
21 | e72c3f2e | Michael Roth | #include "qemu-queue.h" |
22 | e72c3f2e | Michael Roth | #include "host-utils.h" |
23 | 4eb36d40 | Anthony Liguori | |
24 | 2c02cbf6 | Luiz Capitulino | #ifndef CONFIG_HAS_ENVIRON
|
25 | eecae147 | Andreas Färber | #ifdef __APPLE__
|
26 | eecae147 | Andreas Färber | #include <crt_externs.h> |
27 | eecae147 | Andreas Färber | #define environ (*_NSGetEnviron())
|
28 | eecae147 | Andreas Färber | #else
|
29 | 2c02cbf6 | Luiz Capitulino | extern char **environ; |
30 | 2c02cbf6 | Luiz Capitulino | #endif
|
31 | eecae147 | Andreas Färber | #endif
|
32 | 2c02cbf6 | Luiz Capitulino | |
33 | 4eb36d40 | Anthony Liguori | #if defined(__linux__)
|
34 | e3d4d252 | Michael Roth | #include <mntent.h> |
35 | 7006b9cf | Anthony Liguori | #include <linux/fs.h> |
36 | 3424fc9f | Michal Privoznik | #include <ifaddrs.h> |
37 | 3424fc9f | Michal Privoznik | #include <arpa/inet.h> |
38 | 3424fc9f | Michal Privoznik | #include <sys/socket.h> |
39 | 3424fc9f | Michal Privoznik | #include <net/if.h> |
40 | e3d4d252 | Michael Roth | |
41 | eab5fd59 | Paolo Bonzini | #ifdef FIFREEZE
|
42 | e72c3f2e | Michael Roth | #define CONFIG_FSFREEZE
|
43 | e72c3f2e | Michael Roth | #endif
|
44 | eab5fd59 | Paolo Bonzini | #ifdef FITRIM
|
45 | eab5fd59 | Paolo Bonzini | #define CONFIG_FSTRIM
|
46 | eab5fd59 | Paolo Bonzini | #endif
|
47 | e72c3f2e | Michael Roth | #endif
|
48 | e72c3f2e | Michael Roth | |
49 | e3d4d252 | Michael Roth | void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) |
50 | e3d4d252 | Michael Roth | { |
51 | e3d4d252 | Michael Roth | const char *shutdown_flag; |
52 | d5dd3498 | Luiz Capitulino | pid_t rpid, pid; |
53 | 3674838c | Luiz Capitulino | int status;
|
54 | e3d4d252 | Michael Roth | |
55 | e3d4d252 | Michael Roth | slog("guest-shutdown called, mode: %s", mode);
|
56 | e3d4d252 | Michael Roth | if (!has_mode || strcmp(mode, "powerdown") == 0) { |
57 | e3d4d252 | Michael Roth | shutdown_flag = "-P";
|
58 | e3d4d252 | Michael Roth | } else if (strcmp(mode, "halt") == 0) { |
59 | e3d4d252 | Michael Roth | shutdown_flag = "-H";
|
60 | e3d4d252 | Michael Roth | } else if (strcmp(mode, "reboot") == 0) { |
61 | e3d4d252 | Michael Roth | shutdown_flag = "-r";
|
62 | e3d4d252 | Michael Roth | } else {
|
63 | e3d4d252 | Michael Roth | error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
|
64 | e3d4d252 | Michael Roth | "halt|powerdown|reboot");
|
65 | e3d4d252 | Michael Roth | return;
|
66 | e3d4d252 | Michael Roth | } |
67 | e3d4d252 | Michael Roth | |
68 | d5dd3498 | Luiz Capitulino | pid = fork(); |
69 | d5dd3498 | Luiz Capitulino | if (pid == 0) { |
70 | e3d4d252 | Michael Roth | /* child, start the shutdown */
|
71 | e3d4d252 | Michael Roth | setsid(); |
72 | 3674838c | Luiz Capitulino | reopen_fd_to_null(0);
|
73 | 3674838c | Luiz Capitulino | reopen_fd_to_null(1);
|
74 | 3674838c | Luiz Capitulino | reopen_fd_to_null(2);
|
75 | e3d4d252 | Michael Roth | |
76 | 3674838c | Luiz Capitulino | execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0", |
77 | 3674838c | Luiz Capitulino | "hypervisor initiated shutdown", (char*)NULL, environ); |
78 | 3674838c | Luiz Capitulino | _exit(EXIT_FAILURE); |
79 | d5dd3498 | Luiz Capitulino | } else if (pid < 0) { |
80 | d5dd3498 | Luiz Capitulino | goto exit_err;
|
81 | e3d4d252 | Michael Roth | } |
82 | d5dd3498 | Luiz Capitulino | |
83 | d5dd3498 | Luiz Capitulino | do {
|
84 | d5dd3498 | Luiz Capitulino | rpid = waitpid(pid, &status, 0);
|
85 | d5dd3498 | Luiz Capitulino | } while (rpid == -1 && errno == EINTR); |
86 | d5dd3498 | Luiz Capitulino | if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
|
87 | d5dd3498 | Luiz Capitulino | return;
|
88 | d5dd3498 | Luiz Capitulino | } |
89 | d5dd3498 | Luiz Capitulino | |
90 | d5dd3498 | Luiz Capitulino | exit_err:
|
91 | d5dd3498 | Luiz Capitulino | error_set(err, QERR_UNDEFINED_ERROR); |
92 | e3d4d252 | Michael Roth | } |
93 | e3d4d252 | Michael Roth | |
94 | e3d4d252 | Michael Roth | typedef struct GuestFileHandle { |
95 | e3d4d252 | Michael Roth | uint64_t id; |
96 | e3d4d252 | Michael Roth | FILE *fh; |
97 | e3d4d252 | Michael Roth | QTAILQ_ENTRY(GuestFileHandle) next; |
98 | e3d4d252 | Michael Roth | } GuestFileHandle; |
99 | e3d4d252 | Michael Roth | |
100 | e3d4d252 | Michael Roth | static struct { |
101 | e3d4d252 | Michael Roth | QTAILQ_HEAD(, GuestFileHandle) filehandles; |
102 | e3d4d252 | Michael Roth | } guest_file_state; |
103 | e3d4d252 | Michael Roth | |
104 | e3d4d252 | Michael Roth | static void guest_file_handle_add(FILE *fh) |
105 | e3d4d252 | Michael Roth | { |
106 | e3d4d252 | Michael Roth | GuestFileHandle *gfh; |
107 | e3d4d252 | Michael Roth | |
108 | 7267c094 | Anthony Liguori | gfh = g_malloc0(sizeof(GuestFileHandle));
|
109 | e3d4d252 | Michael Roth | gfh->id = fileno(fh); |
110 | e3d4d252 | Michael Roth | gfh->fh = fh; |
111 | e3d4d252 | Michael Roth | QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); |
112 | e3d4d252 | Michael Roth | } |
113 | e3d4d252 | Michael Roth | |
114 | e3d4d252 | Michael Roth | static GuestFileHandle *guest_file_handle_find(int64_t id)
|
115 | e3d4d252 | Michael Roth | { |
116 | e3d4d252 | Michael Roth | GuestFileHandle *gfh; |
117 | e3d4d252 | Michael Roth | |
118 | e3d4d252 | Michael Roth | QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) |
119 | e3d4d252 | Michael Roth | { |
120 | e3d4d252 | Michael Roth | if (gfh->id == id) {
|
121 | e3d4d252 | Michael Roth | return gfh;
|
122 | e3d4d252 | Michael Roth | } |
123 | e3d4d252 | Michael Roth | } |
124 | e3d4d252 | Michael Roth | |
125 | e3d4d252 | Michael Roth | return NULL; |
126 | e3d4d252 | Michael Roth | } |
127 | e3d4d252 | Michael Roth | |
128 | e3d4d252 | Michael Roth | int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err) |
129 | e3d4d252 | Michael Roth | { |
130 | e3d4d252 | Michael Roth | FILE *fh; |
131 | e3d4d252 | Michael Roth | int fd;
|
132 | e3d4d252 | Michael Roth | int64_t ret = -1;
|
133 | e3d4d252 | Michael Roth | |
134 | e3d4d252 | Michael Roth | if (!has_mode) {
|
135 | e3d4d252 | Michael Roth | mode = "r";
|
136 | e3d4d252 | Michael Roth | } |
137 | e3d4d252 | Michael Roth | slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
|
138 | e3d4d252 | Michael Roth | fh = fopen(path, mode); |
139 | e3d4d252 | Michael Roth | if (!fh) {
|
140 | e3d4d252 | Michael Roth | error_set(err, QERR_OPEN_FILE_FAILED, path); |
141 | e3d4d252 | Michael Roth | return -1; |
142 | e3d4d252 | Michael Roth | } |
143 | e3d4d252 | Michael Roth | |
144 | e3d4d252 | Michael Roth | /* set fd non-blocking to avoid common use cases (like reading from a
|
145 | e3d4d252 | Michael Roth | * named pipe) from hanging the agent
|
146 | e3d4d252 | Michael Roth | */
|
147 | e3d4d252 | Michael Roth | fd = fileno(fh); |
148 | e3d4d252 | Michael Roth | ret = fcntl(fd, F_GETFL); |
149 | e3d4d252 | Michael Roth | ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK); |
150 | e3d4d252 | Michael Roth | if (ret == -1) { |
151 | e3d4d252 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
|
152 | e3d4d252 | Michael Roth | fclose(fh); |
153 | e3d4d252 | Michael Roth | return -1; |
154 | e3d4d252 | Michael Roth | } |
155 | e3d4d252 | Michael Roth | |
156 | e3d4d252 | Michael Roth | guest_file_handle_add(fh); |
157 | e3d4d252 | Michael Roth | slog("guest-file-open, handle: %d", fd);
|
158 | e3d4d252 | Michael Roth | return fd;
|
159 | e3d4d252 | Michael Roth | } |
160 | e3d4d252 | Michael Roth | |
161 | e3d4d252 | Michael Roth | void qmp_guest_file_close(int64_t handle, Error **err)
|
162 | e3d4d252 | Michael Roth | { |
163 | e3d4d252 | Michael Roth | GuestFileHandle *gfh = guest_file_handle_find(handle); |
164 | e3d4d252 | Michael Roth | int ret;
|
165 | e3d4d252 | Michael Roth | |
166 | e3d4d252 | Michael Roth | slog("guest-file-close called, handle: %ld", handle);
|
167 | e3d4d252 | Michael Roth | if (!gfh) {
|
168 | e3d4d252 | Michael Roth | error_set(err, QERR_FD_NOT_FOUND, "handle");
|
169 | e3d4d252 | Michael Roth | return;
|
170 | e3d4d252 | Michael Roth | } |
171 | e3d4d252 | Michael Roth | |
172 | e3d4d252 | Michael Roth | ret = fclose(gfh->fh); |
173 | e3d4d252 | Michael Roth | if (ret == -1) { |
174 | e3d4d252 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
|
175 | e3d4d252 | Michael Roth | return;
|
176 | e3d4d252 | Michael Roth | } |
177 | e3d4d252 | Michael Roth | |
178 | e3d4d252 | Michael Roth | QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next); |
179 | 7267c094 | Anthony Liguori | g_free(gfh); |
180 | e3d4d252 | Michael Roth | } |
181 | e3d4d252 | Michael Roth | |
182 | e3d4d252 | Michael Roth | struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, |
183 | e3d4d252 | Michael Roth | int64_t count, Error **err) |
184 | e3d4d252 | Michael Roth | { |
185 | e3d4d252 | Michael Roth | GuestFileHandle *gfh = guest_file_handle_find(handle); |
186 | e3d4d252 | Michael Roth | GuestFileRead *read_data = NULL;
|
187 | e3d4d252 | Michael Roth | guchar *buf; |
188 | e3d4d252 | Michael Roth | FILE *fh; |
189 | e3d4d252 | Michael Roth | size_t read_count; |
190 | e3d4d252 | Michael Roth | |
191 | e3d4d252 | Michael Roth | if (!gfh) {
|
192 | e3d4d252 | Michael Roth | error_set(err, QERR_FD_NOT_FOUND, "handle");
|
193 | e3d4d252 | Michael Roth | return NULL; |
194 | e3d4d252 | Michael Roth | } |
195 | e3d4d252 | Michael Roth | |
196 | e3d4d252 | Michael Roth | if (!has_count) {
|
197 | e3d4d252 | Michael Roth | count = QGA_READ_COUNT_DEFAULT; |
198 | e3d4d252 | Michael Roth | } else if (count < 0) { |
199 | e3d4d252 | Michael Roth | error_set(err, QERR_INVALID_PARAMETER, "count");
|
200 | e3d4d252 | Michael Roth | return NULL; |
201 | e3d4d252 | Michael Roth | } |
202 | e3d4d252 | Michael Roth | |
203 | e3d4d252 | Michael Roth | fh = gfh->fh; |
204 | 7267c094 | Anthony Liguori | buf = g_malloc0(count+1);
|
205 | e3d4d252 | Michael Roth | read_count = fread(buf, 1, count, fh);
|
206 | e3d4d252 | Michael Roth | if (ferror(fh)) {
|
207 | e3d4d252 | Michael Roth | slog("guest-file-read failed, handle: %ld", handle);
|
208 | e3d4d252 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
|
209 | e3d4d252 | Michael Roth | } else {
|
210 | e3d4d252 | Michael Roth | buf[read_count] = 0;
|
211 | 7267c094 | Anthony Liguori | read_data = g_malloc0(sizeof(GuestFileRead));
|
212 | e3d4d252 | Michael Roth | read_data->count = read_count; |
213 | e3d4d252 | Michael Roth | read_data->eof = feof(fh); |
214 | e3d4d252 | Michael Roth | if (read_count) {
|
215 | e3d4d252 | Michael Roth | read_data->buf_b64 = g_base64_encode(buf, read_count); |
216 | e3d4d252 | Michael Roth | } |
217 | e3d4d252 | Michael Roth | } |
218 | 7267c094 | Anthony Liguori | g_free(buf); |
219 | e3d4d252 | Michael Roth | clearerr(fh); |
220 | e3d4d252 | Michael Roth | |
221 | e3d4d252 | Michael Roth | return read_data;
|
222 | e3d4d252 | Michael Roth | } |
223 | e3d4d252 | Michael Roth | |
224 | e3d4d252 | Michael Roth | GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, |
225 | e3d4d252 | Michael Roth | bool has_count, int64_t count, Error **err)
|
226 | e3d4d252 | Michael Roth | { |
227 | e3d4d252 | Michael Roth | GuestFileWrite *write_data = NULL;
|
228 | e3d4d252 | Michael Roth | guchar *buf; |
229 | e3d4d252 | Michael Roth | gsize buf_len; |
230 | e3d4d252 | Michael Roth | int write_count;
|
231 | e3d4d252 | Michael Roth | GuestFileHandle *gfh = guest_file_handle_find(handle); |
232 | e3d4d252 | Michael Roth | FILE *fh; |
233 | e3d4d252 | Michael Roth | |
234 | e3d4d252 | Michael Roth | if (!gfh) {
|
235 | e3d4d252 | Michael Roth | error_set(err, QERR_FD_NOT_FOUND, "handle");
|
236 | e3d4d252 | Michael Roth | return NULL; |
237 | e3d4d252 | Michael Roth | } |
238 | e3d4d252 | Michael Roth | |
239 | e3d4d252 | Michael Roth | fh = gfh->fh; |
240 | e3d4d252 | Michael Roth | buf = g_base64_decode(buf_b64, &buf_len); |
241 | e3d4d252 | Michael Roth | |
242 | e3d4d252 | Michael Roth | if (!has_count) {
|
243 | e3d4d252 | Michael Roth | count = buf_len; |
244 | e3d4d252 | Michael Roth | } else if (count < 0 || count > buf_len) { |
245 | 7267c094 | Anthony Liguori | g_free(buf); |
246 | e3d4d252 | Michael Roth | error_set(err, QERR_INVALID_PARAMETER, "count");
|
247 | e3d4d252 | Michael Roth | return NULL; |
248 | e3d4d252 | Michael Roth | } |
249 | e3d4d252 | Michael Roth | |
250 | e3d4d252 | Michael Roth | write_count = fwrite(buf, 1, count, fh);
|
251 | e3d4d252 | Michael Roth | if (ferror(fh)) {
|
252 | e3d4d252 | Michael Roth | slog("guest-file-write failed, handle: %ld", handle);
|
253 | e3d4d252 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
|
254 | e3d4d252 | Michael Roth | } else {
|
255 | 7267c094 | Anthony Liguori | write_data = g_malloc0(sizeof(GuestFileWrite));
|
256 | e3d4d252 | Michael Roth | write_data->count = write_count; |
257 | e3d4d252 | Michael Roth | write_data->eof = feof(fh); |
258 | e3d4d252 | Michael Roth | } |
259 | 7267c094 | Anthony Liguori | g_free(buf); |
260 | e3d4d252 | Michael Roth | clearerr(fh); |
261 | e3d4d252 | Michael Roth | |
262 | e3d4d252 | Michael Roth | return write_data;
|
263 | e3d4d252 | Michael Roth | } |
264 | e3d4d252 | Michael Roth | |
265 | e3d4d252 | Michael Roth | struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
|
266 | e3d4d252 | Michael Roth | int64_t whence, Error **err) |
267 | e3d4d252 | Michael Roth | { |
268 | e3d4d252 | Michael Roth | GuestFileHandle *gfh = guest_file_handle_find(handle); |
269 | e3d4d252 | Michael Roth | GuestFileSeek *seek_data = NULL;
|
270 | e3d4d252 | Michael Roth | FILE *fh; |
271 | e3d4d252 | Michael Roth | int ret;
|
272 | e3d4d252 | Michael Roth | |
273 | e3d4d252 | Michael Roth | if (!gfh) {
|
274 | e3d4d252 | Michael Roth | error_set(err, QERR_FD_NOT_FOUND, "handle");
|
275 | e3d4d252 | Michael Roth | return NULL; |
276 | e3d4d252 | Michael Roth | } |
277 | e3d4d252 | Michael Roth | |
278 | e3d4d252 | Michael Roth | fh = gfh->fh; |
279 | e3d4d252 | Michael Roth | ret = fseek(fh, offset, whence); |
280 | e3d4d252 | Michael Roth | if (ret == -1) { |
281 | e3d4d252 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); |
282 | e3d4d252 | Michael Roth | } else {
|
283 | 7267c094 | Anthony Liguori | seek_data = g_malloc0(sizeof(GuestFileRead));
|
284 | e3d4d252 | Michael Roth | seek_data->position = ftell(fh); |
285 | e3d4d252 | Michael Roth | seek_data->eof = feof(fh); |
286 | e3d4d252 | Michael Roth | } |
287 | e3d4d252 | Michael Roth | clearerr(fh); |
288 | e3d4d252 | Michael Roth | |
289 | e3d4d252 | Michael Roth | return seek_data;
|
290 | e3d4d252 | Michael Roth | } |
291 | e3d4d252 | Michael Roth | |
292 | e3d4d252 | Michael Roth | void qmp_guest_file_flush(int64_t handle, Error **err)
|
293 | e3d4d252 | Michael Roth | { |
294 | e3d4d252 | Michael Roth | GuestFileHandle *gfh = guest_file_handle_find(handle); |
295 | e3d4d252 | Michael Roth | FILE *fh; |
296 | e3d4d252 | Michael Roth | int ret;
|
297 | e3d4d252 | Michael Roth | |
298 | e3d4d252 | Michael Roth | if (!gfh) {
|
299 | e3d4d252 | Michael Roth | error_set(err, QERR_FD_NOT_FOUND, "handle");
|
300 | e3d4d252 | Michael Roth | return;
|
301 | e3d4d252 | Michael Roth | } |
302 | e3d4d252 | Michael Roth | |
303 | e3d4d252 | Michael Roth | fh = gfh->fh; |
304 | e3d4d252 | Michael Roth | ret = fflush(fh); |
305 | e3d4d252 | Michael Roth | if (ret == EOF) { |
306 | e3d4d252 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); |
307 | e3d4d252 | Michael Roth | } |
308 | e3d4d252 | Michael Roth | } |
309 | e3d4d252 | Michael Roth | |
310 | e3d4d252 | Michael Roth | static void guest_file_init(void) |
311 | e3d4d252 | Michael Roth | { |
312 | e3d4d252 | Michael Roth | QTAILQ_INIT(&guest_file_state.filehandles); |
313 | e3d4d252 | Michael Roth | } |
314 | e3d4d252 | Michael Roth | |
315 | e72c3f2e | Michael Roth | /* linux-specific implementations. avoid this if at all possible. */
|
316 | e72c3f2e | Michael Roth | #if defined(__linux__)
|
317 | e72c3f2e | Michael Roth | |
318 | eab5fd59 | Paolo Bonzini | #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
|
319 | af02203f | Paolo Bonzini | typedef struct FsMount { |
320 | e3d4d252 | Michael Roth | char *dirname;
|
321 | e3d4d252 | Michael Roth | char *devtype;
|
322 | af02203f | Paolo Bonzini | QTAILQ_ENTRY(FsMount) next; |
323 | af02203f | Paolo Bonzini | } FsMount; |
324 | e3d4d252 | Michael Roth | |
325 | af02203f | Paolo Bonzini | typedef QTAILQ_HEAD(, FsMount) FsMountList;
|
326 | 9e8aded4 | Michael Roth | |
327 | af02203f | Paolo Bonzini | static void free_fs_mount_list(FsMountList *mounts) |
328 | 9e8aded4 | Michael Roth | { |
329 | af02203f | Paolo Bonzini | FsMount *mount, *temp; |
330 | 9e8aded4 | Michael Roth | |
331 | 9e8aded4 | Michael Roth | if (!mounts) {
|
332 | 9e8aded4 | Michael Roth | return;
|
333 | 9e8aded4 | Michael Roth | } |
334 | 9e8aded4 | Michael Roth | |
335 | 9e8aded4 | Michael Roth | QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) { |
336 | 9e8aded4 | Michael Roth | QTAILQ_REMOVE(mounts, mount, next); |
337 | 9e8aded4 | Michael Roth | g_free(mount->dirname); |
338 | 9e8aded4 | Michael Roth | g_free(mount->devtype); |
339 | 9e8aded4 | Michael Roth | g_free(mount); |
340 | 9e8aded4 | Michael Roth | } |
341 | 9e8aded4 | Michael Roth | } |
342 | 9e8aded4 | Michael Roth | |
343 | e3d4d252 | Michael Roth | /*
|
344 | e3d4d252 | Michael Roth | * Walk the mount table and build a list of local file systems
|
345 | e3d4d252 | Michael Roth | */
|
346 | af02203f | Paolo Bonzini | static int build_fs_mount_list(FsMountList *mounts) |
347 | e3d4d252 | Michael Roth | { |
348 | e3d4d252 | Michael Roth | struct mntent *ment;
|
349 | af02203f | Paolo Bonzini | FsMount *mount; |
350 | 9e2fa418 | Michael Roth | char const *mtab = "/proc/self/mounts"; |
351 | e3d4d252 | Michael Roth | FILE *fp; |
352 | e3d4d252 | Michael Roth | |
353 | e3d4d252 | Michael Roth | fp = setmntent(mtab, "r");
|
354 | e3d4d252 | Michael Roth | if (!fp) {
|
355 | e3d4d252 | Michael Roth | g_warning("fsfreeze: unable to read mtab");
|
356 | e3d4d252 | Michael Roth | return -1; |
357 | e3d4d252 | Michael Roth | } |
358 | e3d4d252 | Michael Roth | |
359 | e3d4d252 | Michael Roth | while ((ment = getmntent(fp))) {
|
360 | e3d4d252 | Michael Roth | /*
|
361 | e3d4d252 | Michael Roth | * An entry which device name doesn't start with a '/' is
|
362 | e3d4d252 | Michael Roth | * either a dummy file system or a network file system.
|
363 | e3d4d252 | Michael Roth | * Add special handling for smbfs and cifs as is done by
|
364 | e3d4d252 | Michael Roth | * coreutils as well.
|
365 | e3d4d252 | Michael Roth | */
|
366 | e3d4d252 | Michael Roth | if ((ment->mnt_fsname[0] != '/') || |
367 | e3d4d252 | Michael Roth | (strcmp(ment->mnt_type, "smbfs") == 0) || |
368 | e3d4d252 | Michael Roth | (strcmp(ment->mnt_type, "cifs") == 0)) { |
369 | e3d4d252 | Michael Roth | continue;
|
370 | e3d4d252 | Michael Roth | } |
371 | e3d4d252 | Michael Roth | |
372 | af02203f | Paolo Bonzini | mount = g_malloc0(sizeof(FsMount));
|
373 | 7267c094 | Anthony Liguori | mount->dirname = g_strdup(ment->mnt_dir); |
374 | 7267c094 | Anthony Liguori | mount->devtype = g_strdup(ment->mnt_type); |
375 | e3d4d252 | Michael Roth | |
376 | 9e8aded4 | Michael Roth | QTAILQ_INSERT_TAIL(mounts, mount, next); |
377 | e3d4d252 | Michael Roth | } |
378 | e3d4d252 | Michael Roth | |
379 | e3d4d252 | Michael Roth | endmntent(fp); |
380 | e3d4d252 | Michael Roth | |
381 | e3d4d252 | Michael Roth | return 0; |
382 | e3d4d252 | Michael Roth | } |
383 | eab5fd59 | Paolo Bonzini | #endif
|
384 | eab5fd59 | Paolo Bonzini | |
385 | eab5fd59 | Paolo Bonzini | #if defined(CONFIG_FSFREEZE)
|
386 | e3d4d252 | Michael Roth | |
387 | e3d4d252 | Michael Roth | /*
|
388 | e3d4d252 | Michael Roth | * Return status of freeze/thaw
|
389 | e3d4d252 | Michael Roth | */
|
390 | e3d4d252 | Michael Roth | GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) |
391 | e3d4d252 | Michael Roth | { |
392 | f22d85e9 | Michael Roth | if (ga_is_frozen(ga_state)) {
|
393 | f22d85e9 | Michael Roth | return GUEST_FSFREEZE_STATUS_FROZEN;
|
394 | f22d85e9 | Michael Roth | } |
395 | f22d85e9 | Michael Roth | |
396 | f22d85e9 | Michael Roth | return GUEST_FSFREEZE_STATUS_THAWED;
|
397 | e3d4d252 | Michael Roth | } |
398 | e3d4d252 | Michael Roth | |
399 | e3d4d252 | Michael Roth | /*
|
400 | e3d4d252 | Michael Roth | * Walk list of mounted file systems in the guest, and freeze the ones which
|
401 | e3d4d252 | Michael Roth | * are real local file systems.
|
402 | e3d4d252 | Michael Roth | */
|
403 | e3d4d252 | Michael Roth | int64_t qmp_guest_fsfreeze_freeze(Error **err) |
404 | e3d4d252 | Michael Roth | { |
405 | e3d4d252 | Michael Roth | int ret = 0, i = 0; |
406 | af02203f | Paolo Bonzini | FsMountList mounts; |
407 | af02203f | Paolo Bonzini | struct FsMount *mount;
|
408 | e3d4d252 | Michael Roth | int fd;
|
409 | e3d4d252 | Michael Roth | char err_msg[512]; |
410 | e3d4d252 | Michael Roth | |
411 | e3d4d252 | Michael Roth | slog("guest-fsfreeze called");
|
412 | e3d4d252 | Michael Roth | |
413 | 9e8aded4 | Michael Roth | QTAILQ_INIT(&mounts); |
414 | af02203f | Paolo Bonzini | ret = build_fs_mount_list(&mounts); |
415 | e3d4d252 | Michael Roth | if (ret < 0) { |
416 | e3d4d252 | Michael Roth | return ret;
|
417 | e3d4d252 | Michael Roth | } |
418 | e3d4d252 | Michael Roth | |
419 | e3d4d252 | Michael Roth | /* cannot risk guest agent blocking itself on a write in this state */
|
420 | f22d85e9 | Michael Roth | ga_set_frozen(ga_state); |
421 | e3d4d252 | Michael Roth | |
422 | 9e8aded4 | Michael Roth | QTAILQ_FOREACH(mount, &mounts, next) { |
423 | e3d4d252 | Michael Roth | fd = qemu_open(mount->dirname, O_RDONLY); |
424 | e3d4d252 | Michael Roth | if (fd == -1) { |
425 | 9e8aded4 | Michael Roth | sprintf(err_msg, "failed to open %s, %s", mount->dirname,
|
426 | 9e8aded4 | Michael Roth | strerror(errno)); |
427 | e3d4d252 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); |
428 | e3d4d252 | Michael Roth | goto error;
|
429 | e3d4d252 | Michael Roth | } |
430 | e3d4d252 | Michael Roth | |
431 | e3d4d252 | Michael Roth | /* we try to cull filesytems we know won't work in advance, but other
|
432 | e3d4d252 | Michael Roth | * filesytems may not implement fsfreeze for less obvious reasons.
|
433 | 9e8aded4 | Michael Roth | * these will report EOPNOTSUPP. we simply ignore these when tallying
|
434 | 9e8aded4 | Michael Roth | * the number of frozen filesystems.
|
435 | 9e8aded4 | Michael Roth | *
|
436 | 9e8aded4 | Michael Roth | * any other error means a failure to freeze a filesystem we
|
437 | 9e8aded4 | Michael Roth | * expect to be freezable, so return an error in those cases
|
438 | 9e8aded4 | Michael Roth | * and return system to thawed state.
|
439 | e3d4d252 | Michael Roth | */
|
440 | e3d4d252 | Michael Roth | ret = ioctl(fd, FIFREEZE); |
441 | 9e8aded4 | Michael Roth | if (ret == -1) { |
442 | 9e8aded4 | Michael Roth | if (errno != EOPNOTSUPP) {
|
443 | 9e8aded4 | Michael Roth | sprintf(err_msg, "failed to freeze %s, %s",
|
444 | 9e8aded4 | Michael Roth | mount->dirname, strerror(errno)); |
445 | 9e8aded4 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); |
446 | 9e8aded4 | Michael Roth | close(fd); |
447 | 9e8aded4 | Michael Roth | goto error;
|
448 | 9e8aded4 | Michael Roth | } |
449 | 9e8aded4 | Michael Roth | } else {
|
450 | 9e8aded4 | Michael Roth | i++; |
451 | e3d4d252 | Michael Roth | } |
452 | e3d4d252 | Michael Roth | close(fd); |
453 | e3d4d252 | Michael Roth | } |
454 | e3d4d252 | Michael Roth | |
455 | af02203f | Paolo Bonzini | free_fs_mount_list(&mounts); |
456 | e3d4d252 | Michael Roth | return i;
|
457 | e3d4d252 | Michael Roth | |
458 | e3d4d252 | Michael Roth | error:
|
459 | af02203f | Paolo Bonzini | free_fs_mount_list(&mounts); |
460 | 9e8aded4 | Michael Roth | qmp_guest_fsfreeze_thaw(NULL);
|
461 | e3d4d252 | Michael Roth | return 0; |
462 | e3d4d252 | Michael Roth | } |
463 | e3d4d252 | Michael Roth | |
464 | e3d4d252 | Michael Roth | /*
|
465 | e3d4d252 | Michael Roth | * Walk list of frozen file systems in the guest, and thaw them.
|
466 | e3d4d252 | Michael Roth | */
|
467 | e3d4d252 | Michael Roth | int64_t qmp_guest_fsfreeze_thaw(Error **err) |
468 | e3d4d252 | Michael Roth | { |
469 | e3d4d252 | Michael Roth | int ret;
|
470 | af02203f | Paolo Bonzini | FsMountList mounts; |
471 | af02203f | Paolo Bonzini | FsMount *mount; |
472 | 9e8aded4 | Michael Roth | int fd, i = 0, logged; |
473 | 9e8aded4 | Michael Roth | |
474 | 9e8aded4 | Michael Roth | QTAILQ_INIT(&mounts); |
475 | af02203f | Paolo Bonzini | ret = build_fs_mount_list(&mounts); |
476 | 9e8aded4 | Michael Roth | if (ret) {
|
477 | 9e8aded4 | Michael Roth | error_set(err, QERR_QGA_COMMAND_FAILED, |
478 | 9e8aded4 | Michael Roth | "failed to enumerate filesystems");
|
479 | 9e8aded4 | Michael Roth | return 0; |
480 | 9e8aded4 | Michael Roth | } |
481 | e3d4d252 | Michael Roth | |
482 | 9e8aded4 | Michael Roth | QTAILQ_FOREACH(mount, &mounts, next) { |
483 | 9e8aded4 | Michael Roth | logged = false;
|
484 | e3d4d252 | Michael Roth | fd = qemu_open(mount->dirname, O_RDONLY); |
485 | e3d4d252 | Michael Roth | if (fd == -1) { |
486 | e3d4d252 | Michael Roth | continue;
|
487 | e3d4d252 | Michael Roth | } |
488 | 9e8aded4 | Michael Roth | /* we have no way of knowing whether a filesystem was actually unfrozen
|
489 | 9e8aded4 | Michael Roth | * as a result of a successful call to FITHAW, only that if an error
|
490 | 9e8aded4 | Michael Roth | * was returned the filesystem was *not* unfrozen by that particular
|
491 | 9e8aded4 | Michael Roth | * call.
|
492 | 9e8aded4 | Michael Roth | *
|
493 | a31f0531 | Jim Meyering | * since multiple preceding FIFREEZEs require multiple calls to FITHAW
|
494 | 9e8aded4 | Michael Roth | * to unfreeze, continuing issuing FITHAW until an error is returned,
|
495 | 9e8aded4 | Michael Roth | * in which case either the filesystem is in an unfreezable state, or,
|
496 | 9e8aded4 | Michael Roth | * more likely, it was thawed previously (and remains so afterward).
|
497 | 9e8aded4 | Michael Roth | *
|
498 | 9e8aded4 | Michael Roth | * also, since the most recent successful call is the one that did
|
499 | 9e8aded4 | Michael Roth | * the actual unfreeze, we can use this to provide an accurate count
|
500 | 9e8aded4 | Michael Roth | * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
|
501 | 9e8aded4 | Michael Roth | * may * be useful for determining whether a filesystem was unfrozen
|
502 | 9e8aded4 | Michael Roth | * during the freeze/thaw phase by a process other than qemu-ga.
|
503 | 9e8aded4 | Michael Roth | */
|
504 | 9e8aded4 | Michael Roth | do {
|
505 | 9e8aded4 | Michael Roth | ret = ioctl(fd, FITHAW); |
506 | 9e8aded4 | Michael Roth | if (ret == 0 && !logged) { |
507 | 9e8aded4 | Michael Roth | i++; |
508 | 9e8aded4 | Michael Roth | logged = true;
|
509 | 9e8aded4 | Michael Roth | } |
510 | 9e8aded4 | Michael Roth | } while (ret == 0); |
511 | e3d4d252 | Michael Roth | close(fd); |
512 | e3d4d252 | Michael Roth | } |
513 | e3d4d252 | Michael Roth | |
514 | f22d85e9 | Michael Roth | ga_unset_frozen(ga_state); |
515 | af02203f | Paolo Bonzini | free_fs_mount_list(&mounts); |
516 | e3d4d252 | Michael Roth | return i;
|
517 | e3d4d252 | Michael Roth | } |
518 | e3d4d252 | Michael Roth | |
519 | e3d4d252 | Michael Roth | static void guest_fsfreeze_cleanup(void) |
520 | e3d4d252 | Michael Roth | { |
521 | e3d4d252 | Michael Roth | int64_t ret; |
522 | e3d4d252 | Michael Roth | Error *err = NULL;
|
523 | e3d4d252 | Michael Roth | |
524 | f22d85e9 | Michael Roth | if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
|
525 | e3d4d252 | Michael Roth | ret = qmp_guest_fsfreeze_thaw(&err); |
526 | e3d4d252 | Michael Roth | if (ret < 0 || err) { |
527 | e3d4d252 | Michael Roth | slog("failed to clean up frozen filesystems");
|
528 | e3d4d252 | Michael Roth | } |
529 | e3d4d252 | Michael Roth | } |
530 | e3d4d252 | Michael Roth | } |
531 | e72c3f2e | Michael Roth | #endif /* CONFIG_FSFREEZE */ |
532 | e3d4d252 | Michael Roth | |
533 | eab5fd59 | Paolo Bonzini | #if defined(CONFIG_FSTRIM)
|
534 | eab5fd59 | Paolo Bonzini | /*
|
535 | eab5fd59 | Paolo Bonzini | * Walk list of mounted file systems in the guest, and trim them.
|
536 | eab5fd59 | Paolo Bonzini | */
|
537 | eab5fd59 | Paolo Bonzini | void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) |
538 | eab5fd59 | Paolo Bonzini | { |
539 | eab5fd59 | Paolo Bonzini | int ret = 0; |
540 | eab5fd59 | Paolo Bonzini | FsMountList mounts; |
541 | eab5fd59 | Paolo Bonzini | struct FsMount *mount;
|
542 | eab5fd59 | Paolo Bonzini | int fd;
|
543 | eab5fd59 | Paolo Bonzini | char err_msg[512]; |
544 | eab5fd59 | Paolo Bonzini | struct fstrim_range r = {
|
545 | eab5fd59 | Paolo Bonzini | .start = 0,
|
546 | eab5fd59 | Paolo Bonzini | .len = -1,
|
547 | eab5fd59 | Paolo Bonzini | .minlen = has_minimum ? minimum : 0,
|
548 | eab5fd59 | Paolo Bonzini | }; |
549 | eab5fd59 | Paolo Bonzini | |
550 | eab5fd59 | Paolo Bonzini | slog("guest-fstrim called");
|
551 | eab5fd59 | Paolo Bonzini | |
552 | eab5fd59 | Paolo Bonzini | QTAILQ_INIT(&mounts); |
553 | eab5fd59 | Paolo Bonzini | ret = build_fs_mount_list(&mounts); |
554 | eab5fd59 | Paolo Bonzini | if (ret < 0) { |
555 | eab5fd59 | Paolo Bonzini | return;
|
556 | eab5fd59 | Paolo Bonzini | } |
557 | eab5fd59 | Paolo Bonzini | |
558 | eab5fd59 | Paolo Bonzini | QTAILQ_FOREACH(mount, &mounts, next) { |
559 | eab5fd59 | Paolo Bonzini | fd = qemu_open(mount->dirname, O_RDONLY); |
560 | eab5fd59 | Paolo Bonzini | if (fd == -1) { |
561 | eab5fd59 | Paolo Bonzini | sprintf(err_msg, "failed to open %s, %s", mount->dirname,
|
562 | eab5fd59 | Paolo Bonzini | strerror(errno)); |
563 | eab5fd59 | Paolo Bonzini | error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); |
564 | eab5fd59 | Paolo Bonzini | goto error;
|
565 | eab5fd59 | Paolo Bonzini | } |
566 | eab5fd59 | Paolo Bonzini | |
567 | eab5fd59 | Paolo Bonzini | /* We try to cull filesytems we know won't work in advance, but other
|
568 | eab5fd59 | Paolo Bonzini | * filesytems may not implement fstrim for less obvious reasons. These
|
569 | eab5fd59 | Paolo Bonzini | * will report EOPNOTSUPP; we simply ignore these errors. Any other
|
570 | eab5fd59 | Paolo Bonzini | * error means an unexpected error, so return it in those cases. In
|
571 | eab5fd59 | Paolo Bonzini | * some other cases ENOTTY will be reported (e.g. CD-ROMs).
|
572 | eab5fd59 | Paolo Bonzini | */
|
573 | eab5fd59 | Paolo Bonzini | ret = ioctl(fd, FITRIM, &r); |
574 | eab5fd59 | Paolo Bonzini | if (ret == -1) { |
575 | eab5fd59 | Paolo Bonzini | if (errno != ENOTTY && errno != EOPNOTSUPP) {
|
576 | eab5fd59 | Paolo Bonzini | sprintf(err_msg, "failed to trim %s, %s",
|
577 | eab5fd59 | Paolo Bonzini | mount->dirname, strerror(errno)); |
578 | eab5fd59 | Paolo Bonzini | error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); |
579 | eab5fd59 | Paolo Bonzini | close(fd); |
580 | eab5fd59 | Paolo Bonzini | goto error;
|
581 | eab5fd59 | Paolo Bonzini | } |
582 | eab5fd59 | Paolo Bonzini | } |
583 | eab5fd59 | Paolo Bonzini | close(fd); |
584 | eab5fd59 | Paolo Bonzini | } |
585 | eab5fd59 | Paolo Bonzini | |
586 | eab5fd59 | Paolo Bonzini | error:
|
587 | eab5fd59 | Paolo Bonzini | free_fs_mount_list(&mounts); |
588 | eab5fd59 | Paolo Bonzini | } |
589 | eab5fd59 | Paolo Bonzini | #endif /* CONFIG_FSTRIM */ |
590 | eab5fd59 | Paolo Bonzini | |
591 | eab5fd59 | Paolo Bonzini | |
592 | 11d0f125 | Luiz Capitulino | #define LINUX_SYS_STATE_FILE "/sys/power/state" |
593 | 11d0f125 | Luiz Capitulino | #define SUSPEND_SUPPORTED 0 |
594 | 11d0f125 | Luiz Capitulino | #define SUSPEND_NOT_SUPPORTED 1 |
595 | 11d0f125 | Luiz Capitulino | |
596 | 11d0f125 | Luiz Capitulino | static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, |
597 | 11d0f125 | Luiz Capitulino | const char *sysfile_str, Error **err) |
598 | 11d0f125 | Luiz Capitulino | { |
599 | 11d0f125 | Luiz Capitulino | char *pmutils_path;
|
600 | dc8764f0 | Luiz Capitulino | pid_t pid, rpid; |
601 | dc8764f0 | Luiz Capitulino | int status;
|
602 | 11d0f125 | Luiz Capitulino | |
603 | 11d0f125 | Luiz Capitulino | pmutils_path = g_find_program_in_path(pmutils_bin); |
604 | 11d0f125 | Luiz Capitulino | |
605 | 11d0f125 | Luiz Capitulino | pid = fork(); |
606 | 11d0f125 | Luiz Capitulino | if (!pid) {
|
607 | dc8764f0 | Luiz Capitulino | char buf[32]; /* hopefully big enough */ |
608 | dc8764f0 | Luiz Capitulino | ssize_t ret; |
609 | dc8764f0 | Luiz Capitulino | int fd;
|
610 | 11d0f125 | Luiz Capitulino | |
611 | 11d0f125 | Luiz Capitulino | setsid(); |
612 | 11d0f125 | Luiz Capitulino | reopen_fd_to_null(0);
|
613 | 11d0f125 | Luiz Capitulino | reopen_fd_to_null(1);
|
614 | 11d0f125 | Luiz Capitulino | reopen_fd_to_null(2);
|
615 | 11d0f125 | Luiz Capitulino | |
616 | dc8764f0 | Luiz Capitulino | if (pmutils_path) {
|
617 | dc8764f0 | Luiz Capitulino | execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
|
618 | dc8764f0 | Luiz Capitulino | } |
619 | 11d0f125 | Luiz Capitulino | |
620 | dc8764f0 | Luiz Capitulino | /*
|
621 | dc8764f0 | Luiz Capitulino | * If we get here either pm-utils is not installed or execle() has
|
622 | dc8764f0 | Luiz Capitulino | * failed. Let's try the manual method if the caller wants it.
|
623 | dc8764f0 | Luiz Capitulino | */
|
624 | 11d0f125 | Luiz Capitulino | |
625 | dc8764f0 | Luiz Capitulino | if (!sysfile_str) {
|
626 | dc8764f0 | Luiz Capitulino | _exit(SUSPEND_NOT_SUPPORTED); |
627 | dc8764f0 | Luiz Capitulino | } |
628 | 11d0f125 | Luiz Capitulino | |
629 | dc8764f0 | Luiz Capitulino | fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); |
630 | dc8764f0 | Luiz Capitulino | if (fd < 0) { |
631 | 11d0f125 | Luiz Capitulino | _exit(SUSPEND_NOT_SUPPORTED); |
632 | 11d0f125 | Luiz Capitulino | } |
633 | 11d0f125 | Luiz Capitulino | |
634 | dc8764f0 | Luiz Capitulino | ret = read(fd, buf, sizeof(buf)-1); |
635 | dc8764f0 | Luiz Capitulino | if (ret <= 0) { |
636 | dc8764f0 | Luiz Capitulino | _exit(SUSPEND_NOT_SUPPORTED); |
637 | 11d0f125 | Luiz Capitulino | } |
638 | dc8764f0 | Luiz Capitulino | buf[ret] = '\0';
|
639 | 11d0f125 | Luiz Capitulino | |
640 | dc8764f0 | Luiz Capitulino | if (strstr(buf, sysfile_str)) {
|
641 | dc8764f0 | Luiz Capitulino | _exit(SUSPEND_SUPPORTED); |
642 | 11d0f125 | Luiz Capitulino | } |
643 | 11d0f125 | Luiz Capitulino | |
644 | dc8764f0 | Luiz Capitulino | _exit(SUSPEND_NOT_SUPPORTED); |
645 | 11d0f125 | Luiz Capitulino | } |
646 | 11d0f125 | Luiz Capitulino | |
647 | 11d0f125 | Luiz Capitulino | g_free(pmutils_path); |
648 | 11d0f125 | Luiz Capitulino | |
649 | 11d0f125 | Luiz Capitulino | if (pid < 0) { |
650 | dc8764f0 | Luiz Capitulino | goto undef_err;
|
651 | dc8764f0 | Luiz Capitulino | } |
652 | dc8764f0 | Luiz Capitulino | |
653 | dc8764f0 | Luiz Capitulino | do {
|
654 | dc8764f0 | Luiz Capitulino | rpid = waitpid(pid, &status, 0);
|
655 | dc8764f0 | Luiz Capitulino | } while (rpid == -1 && errno == EINTR); |
656 | dc8764f0 | Luiz Capitulino | if (rpid == pid && WIFEXITED(status)) {
|
657 | dc8764f0 | Luiz Capitulino | switch (WEXITSTATUS(status)) {
|
658 | dc8764f0 | Luiz Capitulino | case SUSPEND_SUPPORTED:
|
659 | dc8764f0 | Luiz Capitulino | return;
|
660 | dc8764f0 | Luiz Capitulino | case SUSPEND_NOT_SUPPORTED:
|
661 | dc8764f0 | Luiz Capitulino | error_set(err, QERR_UNSUPPORTED); |
662 | dc8764f0 | Luiz Capitulino | return;
|
663 | dc8764f0 | Luiz Capitulino | default:
|
664 | dc8764f0 | Luiz Capitulino | goto undef_err;
|
665 | dc8764f0 | Luiz Capitulino | } |
666 | 11d0f125 | Luiz Capitulino | } |
667 | 11d0f125 | Luiz Capitulino | |
668 | dc8764f0 | Luiz Capitulino | undef_err:
|
669 | dc8764f0 | Luiz Capitulino | error_set(err, QERR_UNDEFINED_ERROR); |
670 | 11d0f125 | Luiz Capitulino | } |
671 | 11d0f125 | Luiz Capitulino | |
672 | 11d0f125 | Luiz Capitulino | static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, |
673 | 11d0f125 | Luiz Capitulino | Error **err) |
674 | 11d0f125 | Luiz Capitulino | { |
675 | 11d0f125 | Luiz Capitulino | char *pmutils_path;
|
676 | dc8764f0 | Luiz Capitulino | pid_t rpid, pid; |
677 | dc8764f0 | Luiz Capitulino | int status;
|
678 | 11d0f125 | Luiz Capitulino | |
679 | 11d0f125 | Luiz Capitulino | pmutils_path = g_find_program_in_path(pmutils_bin); |
680 | 11d0f125 | Luiz Capitulino | |
681 | 11d0f125 | Luiz Capitulino | pid = fork(); |
682 | 11d0f125 | Luiz Capitulino | if (pid == 0) { |
683 | 11d0f125 | Luiz Capitulino | /* child */
|
684 | 11d0f125 | Luiz Capitulino | int fd;
|
685 | 11d0f125 | Luiz Capitulino | |
686 | 11d0f125 | Luiz Capitulino | setsid(); |
687 | 11d0f125 | Luiz Capitulino | reopen_fd_to_null(0);
|
688 | 11d0f125 | Luiz Capitulino | reopen_fd_to_null(1);
|
689 | 11d0f125 | Luiz Capitulino | reopen_fd_to_null(2);
|
690 | 11d0f125 | Luiz Capitulino | |
691 | 11d0f125 | Luiz Capitulino | if (pmutils_path) {
|
692 | 11d0f125 | Luiz Capitulino | execle(pmutils_path, pmutils_bin, NULL, environ);
|
693 | 11d0f125 | Luiz Capitulino | } |
694 | 11d0f125 | Luiz Capitulino | |
695 | 11d0f125 | Luiz Capitulino | /*
|
696 | 11d0f125 | Luiz Capitulino | * If we get here either pm-utils is not installed or execle() has
|
697 | 11d0f125 | Luiz Capitulino | * failed. Let's try the manual method if the caller wants it.
|
698 | 11d0f125 | Luiz Capitulino | */
|
699 | 11d0f125 | Luiz Capitulino | |
700 | 11d0f125 | Luiz Capitulino | if (!sysfile_str) {
|
701 | 11d0f125 | Luiz Capitulino | _exit(EXIT_FAILURE); |
702 | 11d0f125 | Luiz Capitulino | } |
703 | 11d0f125 | Luiz Capitulino | |
704 | 11d0f125 | Luiz Capitulino | fd = open(LINUX_SYS_STATE_FILE, O_WRONLY); |
705 | 11d0f125 | Luiz Capitulino | if (fd < 0) { |
706 | 11d0f125 | Luiz Capitulino | _exit(EXIT_FAILURE); |
707 | 11d0f125 | Luiz Capitulino | } |
708 | 11d0f125 | Luiz Capitulino | |
709 | 11d0f125 | Luiz Capitulino | if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) { |
710 | 11d0f125 | Luiz Capitulino | _exit(EXIT_FAILURE); |
711 | 11d0f125 | Luiz Capitulino | } |
712 | 11d0f125 | Luiz Capitulino | |
713 | 11d0f125 | Luiz Capitulino | _exit(EXIT_SUCCESS); |
714 | 11d0f125 | Luiz Capitulino | } |
715 | 11d0f125 | Luiz Capitulino | |
716 | 11d0f125 | Luiz Capitulino | g_free(pmutils_path); |
717 | 11d0f125 | Luiz Capitulino | |
718 | 11d0f125 | Luiz Capitulino | if (pid < 0) { |
719 | dc8764f0 | Luiz Capitulino | goto exit_err;
|
720 | dc8764f0 | Luiz Capitulino | } |
721 | dc8764f0 | Luiz Capitulino | |
722 | dc8764f0 | Luiz Capitulino | do {
|
723 | dc8764f0 | Luiz Capitulino | rpid = waitpid(pid, &status, 0);
|
724 | dc8764f0 | Luiz Capitulino | } while (rpid == -1 && errno == EINTR); |
725 | dc8764f0 | Luiz Capitulino | if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
|
726 | 11d0f125 | Luiz Capitulino | return;
|
727 | 11d0f125 | Luiz Capitulino | } |
728 | dc8764f0 | Luiz Capitulino | |
729 | dc8764f0 | Luiz Capitulino | exit_err:
|
730 | dc8764f0 | Luiz Capitulino | error_set(err, QERR_UNDEFINED_ERROR); |
731 | 11d0f125 | Luiz Capitulino | } |
732 | 11d0f125 | Luiz Capitulino | |
733 | 11d0f125 | Luiz Capitulino | void qmp_guest_suspend_disk(Error **err)
|
734 | 11d0f125 | Luiz Capitulino | { |
735 | 11d0f125 | Luiz Capitulino | bios_supports_mode("pm-is-supported", "--hibernate", "disk", err); |
736 | 11d0f125 | Luiz Capitulino | if (error_is_set(err)) {
|
737 | 11d0f125 | Luiz Capitulino | return;
|
738 | 11d0f125 | Luiz Capitulino | } |
739 | 11d0f125 | Luiz Capitulino | |
740 | 11d0f125 | Luiz Capitulino | guest_suspend("pm-hibernate", "disk", err); |
741 | 11d0f125 | Luiz Capitulino | } |
742 | 11d0f125 | Luiz Capitulino | |
743 | fbf42210 | Luiz Capitulino | void qmp_guest_suspend_ram(Error **err)
|
744 | fbf42210 | Luiz Capitulino | { |
745 | fbf42210 | Luiz Capitulino | bios_supports_mode("pm-is-supported", "--suspend", "mem", err); |
746 | fbf42210 | Luiz Capitulino | if (error_is_set(err)) {
|
747 | fbf42210 | Luiz Capitulino | return;
|
748 | fbf42210 | Luiz Capitulino | } |
749 | fbf42210 | Luiz Capitulino | |
750 | fbf42210 | Luiz Capitulino | guest_suspend("pm-suspend", "mem", err); |
751 | fbf42210 | Luiz Capitulino | } |
752 | fbf42210 | Luiz Capitulino | |
753 | 95f4f404 | Luiz Capitulino | void qmp_guest_suspend_hybrid(Error **err)
|
754 | 95f4f404 | Luiz Capitulino | { |
755 | 95f4f404 | Luiz Capitulino | bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err); |
756 | 95f4f404 | Luiz Capitulino | if (error_is_set(err)) {
|
757 | 95f4f404 | Luiz Capitulino | return;
|
758 | 95f4f404 | Luiz Capitulino | } |
759 | 95f4f404 | Luiz Capitulino | |
760 | 95f4f404 | Luiz Capitulino | guest_suspend("pm-suspend-hybrid", NULL, err); |
761 | 95f4f404 | Luiz Capitulino | } |
762 | 95f4f404 | Luiz Capitulino | |
763 | 3424fc9f | Michal Privoznik | static GuestNetworkInterfaceList *
|
764 | 3424fc9f | Michal Privoznik | guest_find_interface(GuestNetworkInterfaceList *head, |
765 | 3424fc9f | Michal Privoznik | const char *name) |
766 | 3424fc9f | Michal Privoznik | { |
767 | 3424fc9f | Michal Privoznik | for (; head; head = head->next) {
|
768 | 3424fc9f | Michal Privoznik | if (strcmp(head->value->name, name) == 0) { |
769 | 3424fc9f | Michal Privoznik | break;
|
770 | 3424fc9f | Michal Privoznik | } |
771 | 3424fc9f | Michal Privoznik | } |
772 | 3424fc9f | Michal Privoznik | |
773 | 3424fc9f | Michal Privoznik | return head;
|
774 | 3424fc9f | Michal Privoznik | } |
775 | 3424fc9f | Michal Privoznik | |
776 | 3424fc9f | Michal Privoznik | /*
|
777 | 3424fc9f | Michal Privoznik | * Build information about guest interfaces
|
778 | 3424fc9f | Michal Privoznik | */
|
779 | 3424fc9f | Michal Privoznik | GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) |
780 | 3424fc9f | Michal Privoznik | { |
781 | 3424fc9f | Michal Privoznik | GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; |
782 | 3424fc9f | Michal Privoznik | struct ifaddrs *ifap, *ifa;
|
783 | 3424fc9f | Michal Privoznik | char err_msg[512]; |
784 | 3424fc9f | Michal Privoznik | |
785 | 3424fc9f | Michal Privoznik | if (getifaddrs(&ifap) < 0) { |
786 | 3424fc9f | Michal Privoznik | snprintf(err_msg, sizeof(err_msg),
|
787 | 3424fc9f | Michal Privoznik | "getifaddrs failed: %s", strerror(errno));
|
788 | 3424fc9f | Michal Privoznik | error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); |
789 | 3424fc9f | Michal Privoznik | goto error;
|
790 | 3424fc9f | Michal Privoznik | } |
791 | 3424fc9f | Michal Privoznik | |
792 | 3424fc9f | Michal Privoznik | for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
793 | 3424fc9f | Michal Privoznik | GuestNetworkInterfaceList *info; |
794 | 3424fc9f | Michal Privoznik | GuestIpAddressList **address_list = NULL, *address_item = NULL; |
795 | 3424fc9f | Michal Privoznik | char addr4[INET_ADDRSTRLEN];
|
796 | 3424fc9f | Michal Privoznik | char addr6[INET6_ADDRSTRLEN];
|
797 | 3424fc9f | Michal Privoznik | int sock;
|
798 | 3424fc9f | Michal Privoznik | struct ifreq ifr;
|
799 | 3424fc9f | Michal Privoznik | unsigned char *mac_addr; |
800 | 3424fc9f | Michal Privoznik | void *p;
|
801 | 3424fc9f | Michal Privoznik | |
802 | 3424fc9f | Michal Privoznik | g_debug("Processing %s interface", ifa->ifa_name);
|
803 | 3424fc9f | Michal Privoznik | |
804 | 3424fc9f | Michal Privoznik | info = guest_find_interface(head, ifa->ifa_name); |
805 | 3424fc9f | Michal Privoznik | |
806 | 3424fc9f | Michal Privoznik | if (!info) {
|
807 | 3424fc9f | Michal Privoznik | info = g_malloc0(sizeof(*info));
|
808 | 3424fc9f | Michal Privoznik | info->value = g_malloc0(sizeof(*info->value));
|
809 | 3424fc9f | Michal Privoznik | info->value->name = g_strdup(ifa->ifa_name); |
810 | 3424fc9f | Michal Privoznik | |
811 | 3424fc9f | Michal Privoznik | if (!cur_item) {
|
812 | 3424fc9f | Michal Privoznik | head = cur_item = info; |
813 | 3424fc9f | Michal Privoznik | } else {
|
814 | 3424fc9f | Michal Privoznik | cur_item->next = info; |
815 | 3424fc9f | Michal Privoznik | cur_item = info; |
816 | 3424fc9f | Michal Privoznik | } |
817 | 3424fc9f | Michal Privoznik | } |
818 | 3424fc9f | Michal Privoznik | |
819 | 3424fc9f | Michal Privoznik | if (!info->value->has_hardware_address &&
|
820 | 3424fc9f | Michal Privoznik | ifa->ifa_flags & SIOCGIFHWADDR) { |
821 | 3424fc9f | Michal Privoznik | /* we haven't obtained HW address yet */
|
822 | 3424fc9f | Michal Privoznik | sock = socket(PF_INET, SOCK_STREAM, 0);
|
823 | 3424fc9f | Michal Privoznik | if (sock == -1) { |
824 | 3424fc9f | Michal Privoznik | snprintf(err_msg, sizeof(err_msg),
|
825 | 3424fc9f | Michal Privoznik | "failed to create socket: %s", strerror(errno));
|
826 | 3424fc9f | Michal Privoznik | error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); |
827 | 3424fc9f | Michal Privoznik | goto error;
|
828 | 3424fc9f | Michal Privoznik | } |
829 | 3424fc9f | Michal Privoznik | |
830 | 3424fc9f | Michal Privoznik | memset(&ifr, 0, sizeof(ifr)); |
831 | 3424fc9f | Michal Privoznik | strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE); |
832 | 3424fc9f | Michal Privoznik | if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { |
833 | 3424fc9f | Michal Privoznik | snprintf(err_msg, sizeof(err_msg),
|
834 | a31f0531 | Jim Meyering | "failed to get MAC address of %s: %s",
|
835 | 3424fc9f | Michal Privoznik | ifa->ifa_name, |
836 | 3424fc9f | Michal Privoznik | strerror(errno)); |
837 | 3424fc9f | Michal Privoznik | error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); |
838 | 3424fc9f | Michal Privoznik | goto error;
|
839 | 3424fc9f | Michal Privoznik | } |
840 | 3424fc9f | Michal Privoznik | |
841 | 3424fc9f | Michal Privoznik | mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; |
842 | 3424fc9f | Michal Privoznik | |
843 | 3424fc9f | Michal Privoznik | if (asprintf(&info->value->hardware_address,
|
844 | 3424fc9f | Michal Privoznik | "%02x:%02x:%02x:%02x:%02x:%02x",
|
845 | 3424fc9f | Michal Privoznik | (int) mac_addr[0], (int) mac_addr[1], |
846 | 3424fc9f | Michal Privoznik | (int) mac_addr[2], (int) mac_addr[3], |
847 | 3424fc9f | Michal Privoznik | (int) mac_addr[4], (int) mac_addr[5]) == -1) { |
848 | 3424fc9f | Michal Privoznik | snprintf(err_msg, sizeof(err_msg),
|
849 | 3424fc9f | Michal Privoznik | "failed to format MAC: %s", strerror(errno));
|
850 | 3424fc9f | Michal Privoznik | error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); |
851 | 3424fc9f | Michal Privoznik | goto error;
|
852 | 3424fc9f | Michal Privoznik | } |
853 | 3424fc9f | Michal Privoznik | |
854 | 3424fc9f | Michal Privoznik | info->value->has_hardware_address = true;
|
855 | 3424fc9f | Michal Privoznik | close(sock); |
856 | 3424fc9f | Michal Privoznik | } |
857 | 3424fc9f | Michal Privoznik | |
858 | 3424fc9f | Michal Privoznik | if (ifa->ifa_addr &&
|
859 | 3424fc9f | Michal Privoznik | ifa->ifa_addr->sa_family == AF_INET) { |
860 | 3424fc9f | Michal Privoznik | /* interface with IPv4 address */
|
861 | 3424fc9f | Michal Privoznik | address_item = g_malloc0(sizeof(*address_item));
|
862 | 3424fc9f | Michal Privoznik | address_item->value = g_malloc0(sizeof(*address_item->value));
|
863 | 3424fc9f | Michal Privoznik | p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
|
864 | 3424fc9f | Michal Privoznik | if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { |
865 | 3424fc9f | Michal Privoznik | snprintf(err_msg, sizeof(err_msg),
|
866 | 3424fc9f | Michal Privoznik | "inet_ntop failed : %s", strerror(errno));
|
867 | 3424fc9f | Michal Privoznik | error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); |
868 | 3424fc9f | Michal Privoznik | goto error;
|
869 | 3424fc9f | Michal Privoznik | } |
870 | 3424fc9f | Michal Privoznik | |
871 | 3424fc9f | Michal Privoznik | address_item->value->ip_address = g_strdup(addr4); |
872 | 3424fc9f | Michal Privoznik | address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; |
873 | 3424fc9f | Michal Privoznik | |
874 | 3424fc9f | Michal Privoznik | if (ifa->ifa_netmask) {
|
875 | 3424fc9f | Michal Privoznik | /* Count the number of set bits in netmask.
|
876 | 3424fc9f | Michal Privoznik | * This is safe as '1' and '0' cannot be shuffled in netmask. */
|
877 | 3424fc9f | Michal Privoznik | p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
|
878 | 3424fc9f | Michal Privoznik | address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
|
879 | 3424fc9f | Michal Privoznik | } |
880 | 3424fc9f | Michal Privoznik | } else if (ifa->ifa_addr && |
881 | 3424fc9f | Michal Privoznik | ifa->ifa_addr->sa_family == AF_INET6) { |
882 | 3424fc9f | Michal Privoznik | /* interface with IPv6 address */
|
883 | 3424fc9f | Michal Privoznik | address_item = g_malloc0(sizeof(*address_item));
|
884 | 3424fc9f | Michal Privoznik | address_item->value = g_malloc0(sizeof(*address_item->value));
|
885 | 3424fc9f | Michal Privoznik | p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
|
886 | 3424fc9f | Michal Privoznik | if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { |
887 | 3424fc9f | Michal Privoznik | snprintf(err_msg, sizeof(err_msg),
|
888 | 3424fc9f | Michal Privoznik | "inet_ntop failed : %s", strerror(errno));
|
889 | 3424fc9f | Michal Privoznik | error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); |
890 | 3424fc9f | Michal Privoznik | goto error;
|
891 | 3424fc9f | Michal Privoznik | } |
892 | 3424fc9f | Michal Privoznik | |
893 | 3424fc9f | Michal Privoznik | address_item->value->ip_address = g_strdup(addr6); |
894 | 3424fc9f | Michal Privoznik | address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; |
895 | 3424fc9f | Michal Privoznik | |
896 | 3424fc9f | Michal Privoznik | if (ifa->ifa_netmask) {
|
897 | 3424fc9f | Michal Privoznik | /* Count the number of set bits in netmask.
|
898 | 3424fc9f | Michal Privoznik | * This is safe as '1' and '0' cannot be shuffled in netmask. */
|
899 | 3424fc9f | Michal Privoznik | p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
|
900 | 3424fc9f | Michal Privoznik | address_item->value->prefix = |
901 | 3424fc9f | Michal Privoznik | ctpop32(((uint32_t *) p)[0]) +
|
902 | 3424fc9f | Michal Privoznik | ctpop32(((uint32_t *) p)[1]) +
|
903 | 3424fc9f | Michal Privoznik | ctpop32(((uint32_t *) p)[2]) +
|
904 | 3424fc9f | Michal Privoznik | ctpop32(((uint32_t *) p)[3]);
|
905 | 3424fc9f | Michal Privoznik | } |
906 | 3424fc9f | Michal Privoznik | } |
907 | 3424fc9f | Michal Privoznik | |
908 | 3424fc9f | Michal Privoznik | if (!address_item) {
|
909 | 3424fc9f | Michal Privoznik | continue;
|
910 | 3424fc9f | Michal Privoznik | } |
911 | 3424fc9f | Michal Privoznik | |
912 | 3424fc9f | Michal Privoznik | address_list = &info->value->ip_addresses; |
913 | 3424fc9f | Michal Privoznik | |
914 | 3424fc9f | Michal Privoznik | while (*address_list && (*address_list)->next) {
|
915 | 3424fc9f | Michal Privoznik | address_list = &(*address_list)->next; |
916 | 3424fc9f | Michal Privoznik | } |
917 | 3424fc9f | Michal Privoznik | |
918 | 3424fc9f | Michal Privoznik | if (!*address_list) {
|
919 | 3424fc9f | Michal Privoznik | *address_list = address_item; |
920 | 3424fc9f | Michal Privoznik | } else {
|
921 | 3424fc9f | Michal Privoznik | (*address_list)->next = address_item; |
922 | 3424fc9f | Michal Privoznik | } |
923 | 3424fc9f | Michal Privoznik | |
924 | 3424fc9f | Michal Privoznik | info->value->has_ip_addresses = true;
|
925 | 3424fc9f | Michal Privoznik | |
926 | 3424fc9f | Michal Privoznik | |
927 | 3424fc9f | Michal Privoznik | } |
928 | 3424fc9f | Michal Privoznik | |
929 | 3424fc9f | Michal Privoznik | freeifaddrs(ifap); |
930 | 3424fc9f | Michal Privoznik | return head;
|
931 | 3424fc9f | Michal Privoznik | |
932 | 3424fc9f | Michal Privoznik | error:
|
933 | 3424fc9f | Michal Privoznik | freeifaddrs(ifap); |
934 | 3424fc9f | Michal Privoznik | qapi_free_GuestNetworkInterfaceList(head); |
935 | 3424fc9f | Michal Privoznik | return NULL; |
936 | 3424fc9f | Michal Privoznik | } |
937 | 3424fc9f | Michal Privoznik | |
938 | e72c3f2e | Michael Roth | #else /* defined(__linux__) */ |
939 | e72c3f2e | Michael Roth | |
940 | d35d4cb5 | Michael Roth | void qmp_guest_suspend_disk(Error **err)
|
941 | e72c3f2e | Michael Roth | { |
942 | e72c3f2e | Michael Roth | error_set(err, QERR_UNSUPPORTED); |
943 | e72c3f2e | Michael Roth | } |
944 | e72c3f2e | Michael Roth | |
945 | d35d4cb5 | Michael Roth | void qmp_guest_suspend_ram(Error **err)
|
946 | e72c3f2e | Michael Roth | { |
947 | e72c3f2e | Michael Roth | error_set(err, QERR_UNSUPPORTED); |
948 | e72c3f2e | Michael Roth | } |
949 | e72c3f2e | Michael Roth | |
950 | d35d4cb5 | Michael Roth | void qmp_guest_suspend_hybrid(Error **err)
|
951 | e72c3f2e | Michael Roth | { |
952 | e72c3f2e | Michael Roth | error_set(err, QERR_UNSUPPORTED); |
953 | e72c3f2e | Michael Roth | } |
954 | e72c3f2e | Michael Roth | |
955 | d35d4cb5 | Michael Roth | GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) |
956 | e72c3f2e | Michael Roth | { |
957 | d35d4cb5 | Michael Roth | error_set(errp, QERR_UNSUPPORTED); |
958 | d35d4cb5 | Michael Roth | return NULL; |
959 | e72c3f2e | Michael Roth | } |
960 | e72c3f2e | Michael Roth | |
961 | d35d4cb5 | Michael Roth | #endif
|
962 | d35d4cb5 | Michael Roth | |
963 | d35d4cb5 | Michael Roth | #if !defined(CONFIG_FSFREEZE)
|
964 | d35d4cb5 | Michael Roth | |
965 | d35d4cb5 | Michael Roth | GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) |
966 | e72c3f2e | Michael Roth | { |
967 | e72c3f2e | Michael Roth | error_set(err, QERR_UNSUPPORTED); |
968 | d35d4cb5 | Michael Roth | |
969 | d35d4cb5 | Michael Roth | return 0; |
970 | e72c3f2e | Michael Roth | } |
971 | e72c3f2e | Michael Roth | |
972 | d35d4cb5 | Michael Roth | int64_t qmp_guest_fsfreeze_freeze(Error **err) |
973 | e72c3f2e | Michael Roth | { |
974 | e72c3f2e | Michael Roth | error_set(err, QERR_UNSUPPORTED); |
975 | d35d4cb5 | Michael Roth | |
976 | d35d4cb5 | Michael Roth | return 0; |
977 | e72c3f2e | Michael Roth | } |
978 | e72c3f2e | Michael Roth | |
979 | d35d4cb5 | Michael Roth | int64_t qmp_guest_fsfreeze_thaw(Error **err) |
980 | e72c3f2e | Michael Roth | { |
981 | d35d4cb5 | Michael Roth | error_set(err, QERR_UNSUPPORTED); |
982 | d35d4cb5 | Michael Roth | |
983 | d35d4cb5 | Michael Roth | return 0; |
984 | e72c3f2e | Michael Roth | } |
985 | eab5fd59 | Paolo Bonzini | #endif /* CONFIG_FSFREEZE */ |
986 | eab5fd59 | Paolo Bonzini | |
987 | eab5fd59 | Paolo Bonzini | #if !defined(CONFIG_FSTRIM)
|
988 | eab5fd59 | Paolo Bonzini | void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) |
989 | eab5fd59 | Paolo Bonzini | { |
990 | eab5fd59 | Paolo Bonzini | error_set(err, QERR_UNSUPPORTED); |
991 | e72c3f2e | Michael Roth | |
992 | eab5fd59 | Paolo Bonzini | return;
|
993 | eab5fd59 | Paolo Bonzini | } |
994 | e72c3f2e | Michael Roth | #endif
|
995 | e72c3f2e | Michael Roth | |
996 | e3d4d252 | Michael Roth | /* register init/cleanup routines for stateful command groups */
|
997 | e3d4d252 | Michael Roth | void ga_command_state_init(GAState *s, GACommandState *cs)
|
998 | e3d4d252 | Michael Roth | { |
999 | 7006b9cf | Anthony Liguori | #if defined(CONFIG_FSFREEZE)
|
1000 | f22d85e9 | Michael Roth | ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
|
1001 | 7006b9cf | Anthony Liguori | #endif
|
1002 | e3d4d252 | Michael Roth | ga_command_state_add(cs, guest_file_init, NULL);
|
1003 | e3d4d252 | Michael Roth | } |