Statistics
| Branch: | Revision:

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
}