xref: /openbmc/qemu/qga/commands-posix.c (revision 3424fc9f)
1c216e5adSMichael Roth /*
2c216e5adSMichael Roth  * QEMU Guest Agent POSIX-specific command implementations
3c216e5adSMichael Roth  *
4c216e5adSMichael Roth  * Copyright IBM Corp. 2011
5c216e5adSMichael Roth  *
6c216e5adSMichael Roth  * Authors:
7c216e5adSMichael Roth  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
8*3424fc9fSMichal Privoznik  *  Michal Privoznik  <mprivozn@redhat.com>
9c216e5adSMichael Roth  *
10c216e5adSMichael Roth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11c216e5adSMichael Roth  * See the COPYING file in the top-level directory.
12c216e5adSMichael Roth  */
13c216e5adSMichael Roth 
14c216e5adSMichael Roth #include <glib.h>
15c216e5adSMichael Roth 
16c216e5adSMichael Roth #if defined(__linux__)
17c216e5adSMichael Roth #include <mntent.h>
18c216e5adSMichael Roth #include <linux/fs.h>
19c216e5adSMichael Roth 
20c216e5adSMichael Roth #if defined(__linux__) && defined(FIFREEZE)
21c216e5adSMichael Roth #define CONFIG_FSFREEZE
22c216e5adSMichael Roth #endif
23c216e5adSMichael Roth #endif
24c216e5adSMichael Roth 
25c216e5adSMichael Roth #include <sys/types.h>
26c216e5adSMichael Roth #include <sys/ioctl.h>
27*3424fc9fSMichal Privoznik #include <ifaddrs.h>
28*3424fc9fSMichal Privoznik #include <arpa/inet.h>
29*3424fc9fSMichal Privoznik #include <sys/socket.h>
30*3424fc9fSMichal Privoznik #include <net/if.h>
3111d0f125SLuiz Capitulino #include <sys/wait.h>
32c216e5adSMichael Roth #include "qga/guest-agent-core.h"
33c216e5adSMichael Roth #include "qga-qmp-commands.h"
34c216e5adSMichael Roth #include "qerror.h"
35c216e5adSMichael Roth #include "qemu-queue.h"
36*3424fc9fSMichal Privoznik #include "host-utils.h"
37c216e5adSMichael Roth 
38c216e5adSMichael Roth static GAState *ga_state;
39c216e5adSMichael Roth 
4011d0f125SLuiz Capitulino static void reopen_fd_to_null(int fd)
4111d0f125SLuiz Capitulino {
4211d0f125SLuiz Capitulino     int nullfd;
4311d0f125SLuiz Capitulino 
4411d0f125SLuiz Capitulino     nullfd = open("/dev/null", O_RDWR);
4511d0f125SLuiz Capitulino     if (nullfd < 0) {
4611d0f125SLuiz Capitulino         return;
4711d0f125SLuiz Capitulino     }
4811d0f125SLuiz Capitulino 
4911d0f125SLuiz Capitulino     dup2(nullfd, fd);
5011d0f125SLuiz Capitulino 
5111d0f125SLuiz Capitulino     if (nullfd != fd) {
5211d0f125SLuiz Capitulino         close(nullfd);
5311d0f125SLuiz Capitulino     }
5411d0f125SLuiz Capitulino }
5511d0f125SLuiz Capitulino 
56c216e5adSMichael Roth void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
57c216e5adSMichael Roth {
58c216e5adSMichael Roth     int ret;
59c216e5adSMichael Roth     const char *shutdown_flag;
60c216e5adSMichael Roth 
61c216e5adSMichael Roth     slog("guest-shutdown called, mode: %s", mode);
62c216e5adSMichael Roth     if (!has_mode || strcmp(mode, "powerdown") == 0) {
63c216e5adSMichael Roth         shutdown_flag = "-P";
64c216e5adSMichael Roth     } else if (strcmp(mode, "halt") == 0) {
65c216e5adSMichael Roth         shutdown_flag = "-H";
66c216e5adSMichael Roth     } else if (strcmp(mode, "reboot") == 0) {
67c216e5adSMichael Roth         shutdown_flag = "-r";
68c216e5adSMichael Roth     } else {
69c216e5adSMichael Roth         error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
70c216e5adSMichael Roth                   "halt|powerdown|reboot");
71c216e5adSMichael Roth         return;
72c216e5adSMichael Roth     }
73c216e5adSMichael Roth 
74c216e5adSMichael Roth     ret = fork();
75c216e5adSMichael Roth     if (ret == 0) {
76c216e5adSMichael Roth         /* child, start the shutdown */
77c216e5adSMichael Roth         setsid();
78c216e5adSMichael Roth         fclose(stdin);
79c216e5adSMichael Roth         fclose(stdout);
80c216e5adSMichael Roth         fclose(stderr);
81c216e5adSMichael Roth 
82c216e5adSMichael Roth         ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
83c216e5adSMichael Roth                     "hypervisor initiated shutdown", (char*)NULL);
84c216e5adSMichael Roth         if (ret) {
85c216e5adSMichael Roth             slog("guest-shutdown failed: %s", strerror(errno));
86c216e5adSMichael Roth         }
87c216e5adSMichael Roth         exit(!!ret);
88c216e5adSMichael Roth     } else if (ret < 0) {
89c216e5adSMichael Roth         error_set(err, QERR_UNDEFINED_ERROR);
90c216e5adSMichael Roth     }
91c216e5adSMichael Roth }
92c216e5adSMichael Roth 
93c216e5adSMichael Roth typedef struct GuestFileHandle {
94c216e5adSMichael Roth     uint64_t id;
95c216e5adSMichael Roth     FILE *fh;
96c216e5adSMichael Roth     QTAILQ_ENTRY(GuestFileHandle) next;
97c216e5adSMichael Roth } GuestFileHandle;
98c216e5adSMichael Roth 
99c216e5adSMichael Roth static struct {
100c216e5adSMichael Roth     QTAILQ_HEAD(, GuestFileHandle) filehandles;
101c216e5adSMichael Roth } guest_file_state;
102c216e5adSMichael Roth 
103c216e5adSMichael Roth static void guest_file_handle_add(FILE *fh)
104c216e5adSMichael Roth {
105c216e5adSMichael Roth     GuestFileHandle *gfh;
106c216e5adSMichael Roth 
107c216e5adSMichael Roth     gfh = g_malloc0(sizeof(GuestFileHandle));
108c216e5adSMichael Roth     gfh->id = fileno(fh);
109c216e5adSMichael Roth     gfh->fh = fh;
110c216e5adSMichael Roth     QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
111c216e5adSMichael Roth }
112c216e5adSMichael Roth 
113c216e5adSMichael Roth static GuestFileHandle *guest_file_handle_find(int64_t id)
114c216e5adSMichael Roth {
115c216e5adSMichael Roth     GuestFileHandle *gfh;
116c216e5adSMichael Roth 
117c216e5adSMichael Roth     QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
118c216e5adSMichael Roth     {
119c216e5adSMichael Roth         if (gfh->id == id) {
120c216e5adSMichael Roth             return gfh;
121c216e5adSMichael Roth         }
122c216e5adSMichael Roth     }
123c216e5adSMichael Roth 
124c216e5adSMichael Roth     return NULL;
125c216e5adSMichael Roth }
126c216e5adSMichael Roth 
127c216e5adSMichael Roth int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
128c216e5adSMichael Roth {
129c216e5adSMichael Roth     FILE *fh;
130c216e5adSMichael Roth     int fd;
131c216e5adSMichael Roth     int64_t ret = -1;
132c216e5adSMichael Roth 
133c216e5adSMichael Roth     if (!has_mode) {
134c216e5adSMichael Roth         mode = "r";
135c216e5adSMichael Roth     }
136c216e5adSMichael Roth     slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
137c216e5adSMichael Roth     fh = fopen(path, mode);
138c216e5adSMichael Roth     if (!fh) {
139c216e5adSMichael Roth         error_set(err, QERR_OPEN_FILE_FAILED, path);
140c216e5adSMichael Roth         return -1;
141c216e5adSMichael Roth     }
142c216e5adSMichael Roth 
143c216e5adSMichael Roth     /* set fd non-blocking to avoid common use cases (like reading from a
144c216e5adSMichael Roth      * named pipe) from hanging the agent
145c216e5adSMichael Roth      */
146c216e5adSMichael Roth     fd = fileno(fh);
147c216e5adSMichael Roth     ret = fcntl(fd, F_GETFL);
148c216e5adSMichael Roth     ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
149c216e5adSMichael Roth     if (ret == -1) {
150c216e5adSMichael Roth         error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
151c216e5adSMichael Roth         fclose(fh);
152c216e5adSMichael Roth         return -1;
153c216e5adSMichael Roth     }
154c216e5adSMichael Roth 
155c216e5adSMichael Roth     guest_file_handle_add(fh);
156c216e5adSMichael Roth     slog("guest-file-open, handle: %d", fd);
157c216e5adSMichael Roth     return fd;
158c216e5adSMichael Roth }
159c216e5adSMichael Roth 
160c216e5adSMichael Roth void qmp_guest_file_close(int64_t handle, Error **err)
161c216e5adSMichael Roth {
162c216e5adSMichael Roth     GuestFileHandle *gfh = guest_file_handle_find(handle);
163c216e5adSMichael Roth     int ret;
164c216e5adSMichael Roth 
165c216e5adSMichael Roth     slog("guest-file-close called, handle: %ld", handle);
166c216e5adSMichael Roth     if (!gfh) {
167c216e5adSMichael Roth         error_set(err, QERR_FD_NOT_FOUND, "handle");
168c216e5adSMichael Roth         return;
169c216e5adSMichael Roth     }
170c216e5adSMichael Roth 
171c216e5adSMichael Roth     ret = fclose(gfh->fh);
172c216e5adSMichael Roth     if (ret == -1) {
173c216e5adSMichael Roth         error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
174c216e5adSMichael Roth         return;
175c216e5adSMichael Roth     }
176c216e5adSMichael Roth 
177c216e5adSMichael Roth     QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
178c216e5adSMichael Roth     g_free(gfh);
179c216e5adSMichael Roth }
180c216e5adSMichael Roth 
181c216e5adSMichael Roth struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
182c216e5adSMichael Roth                                           int64_t count, Error **err)
183c216e5adSMichael Roth {
184c216e5adSMichael Roth     GuestFileHandle *gfh = guest_file_handle_find(handle);
185c216e5adSMichael Roth     GuestFileRead *read_data = NULL;
186c216e5adSMichael Roth     guchar *buf;
187c216e5adSMichael Roth     FILE *fh;
188c216e5adSMichael Roth     size_t read_count;
189c216e5adSMichael Roth 
190c216e5adSMichael Roth     if (!gfh) {
191c216e5adSMichael Roth         error_set(err, QERR_FD_NOT_FOUND, "handle");
192c216e5adSMichael Roth         return NULL;
193c216e5adSMichael Roth     }
194c216e5adSMichael Roth 
195c216e5adSMichael Roth     if (!has_count) {
196c216e5adSMichael Roth         count = QGA_READ_COUNT_DEFAULT;
197c216e5adSMichael Roth     } else if (count < 0) {
198c216e5adSMichael Roth         error_set(err, QERR_INVALID_PARAMETER, "count");
199c216e5adSMichael Roth         return NULL;
200c216e5adSMichael Roth     }
201c216e5adSMichael Roth 
202c216e5adSMichael Roth     fh = gfh->fh;
203c216e5adSMichael Roth     buf = g_malloc0(count+1);
204c216e5adSMichael Roth     read_count = fread(buf, 1, count, fh);
205c216e5adSMichael Roth     if (ferror(fh)) {
206c216e5adSMichael Roth         slog("guest-file-read failed, handle: %ld", handle);
207c216e5adSMichael Roth         error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
208c216e5adSMichael Roth     } else {
209c216e5adSMichael Roth         buf[read_count] = 0;
210c216e5adSMichael Roth         read_data = g_malloc0(sizeof(GuestFileRead));
211c216e5adSMichael Roth         read_data->count = read_count;
212c216e5adSMichael Roth         read_data->eof = feof(fh);
213c216e5adSMichael Roth         if (read_count) {
214c216e5adSMichael Roth             read_data->buf_b64 = g_base64_encode(buf, read_count);
215c216e5adSMichael Roth         }
216c216e5adSMichael Roth     }
217c216e5adSMichael Roth     g_free(buf);
218c216e5adSMichael Roth     clearerr(fh);
219c216e5adSMichael Roth 
220c216e5adSMichael Roth     return read_data;
221c216e5adSMichael Roth }
222c216e5adSMichael Roth 
223c216e5adSMichael Roth GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
224c216e5adSMichael Roth                                      bool has_count, int64_t count, Error **err)
225c216e5adSMichael Roth {
226c216e5adSMichael Roth     GuestFileWrite *write_data = NULL;
227c216e5adSMichael Roth     guchar *buf;
228c216e5adSMichael Roth     gsize buf_len;
229c216e5adSMichael Roth     int write_count;
230c216e5adSMichael Roth     GuestFileHandle *gfh = guest_file_handle_find(handle);
231c216e5adSMichael Roth     FILE *fh;
232c216e5adSMichael Roth 
233c216e5adSMichael Roth     if (!gfh) {
234c216e5adSMichael Roth         error_set(err, QERR_FD_NOT_FOUND, "handle");
235c216e5adSMichael Roth         return NULL;
236c216e5adSMichael Roth     }
237c216e5adSMichael Roth 
238c216e5adSMichael Roth     fh = gfh->fh;
239c216e5adSMichael Roth     buf = g_base64_decode(buf_b64, &buf_len);
240c216e5adSMichael Roth 
241c216e5adSMichael Roth     if (!has_count) {
242c216e5adSMichael Roth         count = buf_len;
243c216e5adSMichael Roth     } else if (count < 0 || count > buf_len) {
244c216e5adSMichael Roth         g_free(buf);
245c216e5adSMichael Roth         error_set(err, QERR_INVALID_PARAMETER, "count");
246c216e5adSMichael Roth         return NULL;
247c216e5adSMichael Roth     }
248c216e5adSMichael Roth 
249c216e5adSMichael Roth     write_count = fwrite(buf, 1, count, fh);
250c216e5adSMichael Roth     if (ferror(fh)) {
251c216e5adSMichael Roth         slog("guest-file-write failed, handle: %ld", handle);
252c216e5adSMichael Roth         error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
253c216e5adSMichael Roth     } else {
254c216e5adSMichael Roth         write_data = g_malloc0(sizeof(GuestFileWrite));
255c216e5adSMichael Roth         write_data->count = write_count;
256c216e5adSMichael Roth         write_data->eof = feof(fh);
257c216e5adSMichael Roth     }
258c216e5adSMichael Roth     g_free(buf);
259c216e5adSMichael Roth     clearerr(fh);
260c216e5adSMichael Roth 
261c216e5adSMichael Roth     return write_data;
262c216e5adSMichael Roth }
263c216e5adSMichael Roth 
264c216e5adSMichael Roth struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
265c216e5adSMichael Roth                                           int64_t whence, Error **err)
266c216e5adSMichael Roth {
267c216e5adSMichael Roth     GuestFileHandle *gfh = guest_file_handle_find(handle);
268c216e5adSMichael Roth     GuestFileSeek *seek_data = NULL;
269c216e5adSMichael Roth     FILE *fh;
270c216e5adSMichael Roth     int ret;
271c216e5adSMichael Roth 
272c216e5adSMichael Roth     if (!gfh) {
273c216e5adSMichael Roth         error_set(err, QERR_FD_NOT_FOUND, "handle");
274c216e5adSMichael Roth         return NULL;
275c216e5adSMichael Roth     }
276c216e5adSMichael Roth 
277c216e5adSMichael Roth     fh = gfh->fh;
278c216e5adSMichael Roth     ret = fseek(fh, offset, whence);
279c216e5adSMichael Roth     if (ret == -1) {
280c216e5adSMichael Roth         error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
281c216e5adSMichael Roth     } else {
282c216e5adSMichael Roth         seek_data = g_malloc0(sizeof(GuestFileRead));
283c216e5adSMichael Roth         seek_data->position = ftell(fh);
284c216e5adSMichael Roth         seek_data->eof = feof(fh);
285c216e5adSMichael Roth     }
286c216e5adSMichael Roth     clearerr(fh);
287c216e5adSMichael Roth 
288c216e5adSMichael Roth     return seek_data;
289c216e5adSMichael Roth }
290c216e5adSMichael Roth 
291c216e5adSMichael Roth void qmp_guest_file_flush(int64_t handle, Error **err)
292c216e5adSMichael Roth {
293c216e5adSMichael Roth     GuestFileHandle *gfh = guest_file_handle_find(handle);
294c216e5adSMichael Roth     FILE *fh;
295c216e5adSMichael Roth     int ret;
296c216e5adSMichael Roth 
297c216e5adSMichael Roth     if (!gfh) {
298c216e5adSMichael Roth         error_set(err, QERR_FD_NOT_FOUND, "handle");
299c216e5adSMichael Roth         return;
300c216e5adSMichael Roth     }
301c216e5adSMichael Roth 
302c216e5adSMichael Roth     fh = gfh->fh;
303c216e5adSMichael Roth     ret = fflush(fh);
304c216e5adSMichael Roth     if (ret == EOF) {
305c216e5adSMichael Roth         error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
306c216e5adSMichael Roth     }
307c216e5adSMichael Roth }
308c216e5adSMichael Roth 
309c216e5adSMichael Roth static void guest_file_init(void)
310c216e5adSMichael Roth {
311c216e5adSMichael Roth     QTAILQ_INIT(&guest_file_state.filehandles);
312c216e5adSMichael Roth }
313c216e5adSMichael Roth 
314c216e5adSMichael Roth #if defined(CONFIG_FSFREEZE)
315c216e5adSMichael Roth static void disable_logging(void)
316c216e5adSMichael Roth {
317c216e5adSMichael Roth     ga_disable_logging(ga_state);
318c216e5adSMichael Roth }
319c216e5adSMichael Roth 
320c216e5adSMichael Roth static void enable_logging(void)
321c216e5adSMichael Roth {
322c216e5adSMichael Roth     ga_enable_logging(ga_state);
323c216e5adSMichael Roth }
324c216e5adSMichael Roth 
325c216e5adSMichael Roth typedef struct GuestFsfreezeMount {
326c216e5adSMichael Roth     char *dirname;
327c216e5adSMichael Roth     char *devtype;
328c216e5adSMichael Roth     QTAILQ_ENTRY(GuestFsfreezeMount) next;
329c216e5adSMichael Roth } GuestFsfreezeMount;
330c216e5adSMichael Roth 
331c216e5adSMichael Roth struct {
332c216e5adSMichael Roth     GuestFsfreezeStatus status;
333c216e5adSMichael Roth     QTAILQ_HEAD(, GuestFsfreezeMount) mount_list;
334c216e5adSMichael Roth } guest_fsfreeze_state;
335c216e5adSMichael Roth 
336c216e5adSMichael Roth /*
337c216e5adSMichael Roth  * Walk the mount table and build a list of local file systems
338c216e5adSMichael Roth  */
339c216e5adSMichael Roth static int guest_fsfreeze_build_mount_list(void)
340c216e5adSMichael Roth {
341c216e5adSMichael Roth     struct mntent *ment;
342c216e5adSMichael Roth     GuestFsfreezeMount *mount, *temp;
343c216e5adSMichael Roth     char const *mtab = MOUNTED;
344c216e5adSMichael Roth     FILE *fp;
345c216e5adSMichael Roth 
346c216e5adSMichael Roth     QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
347c216e5adSMichael Roth         QTAILQ_REMOVE(&guest_fsfreeze_state.mount_list, mount, next);
348c216e5adSMichael Roth         g_free(mount->dirname);
349c216e5adSMichael Roth         g_free(mount->devtype);
350c216e5adSMichael Roth         g_free(mount);
351c216e5adSMichael Roth     }
352c216e5adSMichael Roth 
353c216e5adSMichael Roth     fp = setmntent(mtab, "r");
354c216e5adSMichael Roth     if (!fp) {
355c216e5adSMichael Roth         g_warning("fsfreeze: unable to read mtab");
356c216e5adSMichael Roth         return -1;
357c216e5adSMichael Roth     }
358c216e5adSMichael Roth 
359c216e5adSMichael Roth     while ((ment = getmntent(fp))) {
360c216e5adSMichael Roth         /*
361c216e5adSMichael Roth          * An entry which device name doesn't start with a '/' is
362c216e5adSMichael Roth          * either a dummy file system or a network file system.
363c216e5adSMichael Roth          * Add special handling for smbfs and cifs as is done by
364c216e5adSMichael Roth          * coreutils as well.
365c216e5adSMichael Roth          */
366c216e5adSMichael Roth         if ((ment->mnt_fsname[0] != '/') ||
367c216e5adSMichael Roth             (strcmp(ment->mnt_type, "smbfs") == 0) ||
368c216e5adSMichael Roth             (strcmp(ment->mnt_type, "cifs") == 0)) {
369c216e5adSMichael Roth             continue;
370c216e5adSMichael Roth         }
371c216e5adSMichael Roth 
372c216e5adSMichael Roth         mount = g_malloc0(sizeof(GuestFsfreezeMount));
373c216e5adSMichael Roth         mount->dirname = g_strdup(ment->mnt_dir);
374c216e5adSMichael Roth         mount->devtype = g_strdup(ment->mnt_type);
375c216e5adSMichael Roth 
376c216e5adSMichael Roth         QTAILQ_INSERT_TAIL(&guest_fsfreeze_state.mount_list, mount, next);
377c216e5adSMichael Roth     }
378c216e5adSMichael Roth 
379c216e5adSMichael Roth     endmntent(fp);
380c216e5adSMichael Roth 
381c216e5adSMichael Roth     return 0;
382c216e5adSMichael Roth }
383c216e5adSMichael Roth 
384c216e5adSMichael Roth /*
385c216e5adSMichael Roth  * Return status of freeze/thaw
386c216e5adSMichael Roth  */
387c216e5adSMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
388c216e5adSMichael Roth {
389c216e5adSMichael Roth     return guest_fsfreeze_state.status;
390c216e5adSMichael Roth }
391c216e5adSMichael Roth 
392c216e5adSMichael Roth /*
393c216e5adSMichael Roth  * Walk list of mounted file systems in the guest, and freeze the ones which
394c216e5adSMichael Roth  * are real local file systems.
395c216e5adSMichael Roth  */
396c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err)
397c216e5adSMichael Roth {
398c216e5adSMichael Roth     int ret = 0, i = 0;
399c216e5adSMichael Roth     struct GuestFsfreezeMount *mount, *temp;
400c216e5adSMichael Roth     int fd;
401c216e5adSMichael Roth     char err_msg[512];
402c216e5adSMichael Roth 
403c216e5adSMichael Roth     slog("guest-fsfreeze called");
404c216e5adSMichael Roth 
405c216e5adSMichael Roth     if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
406c216e5adSMichael Roth         return 0;
407c216e5adSMichael Roth     }
408c216e5adSMichael Roth 
409c216e5adSMichael Roth     ret = guest_fsfreeze_build_mount_list();
410c216e5adSMichael Roth     if (ret < 0) {
411c216e5adSMichael Roth         return ret;
412c216e5adSMichael Roth     }
413c216e5adSMichael Roth 
414c216e5adSMichael Roth     /* cannot risk guest agent blocking itself on a write in this state */
415c216e5adSMichael Roth     disable_logging();
416c216e5adSMichael Roth 
417c216e5adSMichael Roth     QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
418c216e5adSMichael Roth         fd = qemu_open(mount->dirname, O_RDONLY);
419c216e5adSMichael Roth         if (fd == -1) {
420c216e5adSMichael Roth             sprintf(err_msg, "failed to open %s, %s", mount->dirname, strerror(errno));
421c216e5adSMichael Roth             error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
422c216e5adSMichael Roth             goto error;
423c216e5adSMichael Roth         }
424c216e5adSMichael Roth 
425c216e5adSMichael Roth         /* we try to cull filesytems we know won't work in advance, but other
426c216e5adSMichael Roth          * filesytems may not implement fsfreeze for less obvious reasons.
427c216e5adSMichael Roth          * these will report EOPNOTSUPP, so we simply ignore them. when
428c216e5adSMichael Roth          * thawing, these filesystems will return an EINVAL instead, due to
429c216e5adSMichael Roth          * not being in a frozen state. Other filesystem-specific
430c216e5adSMichael Roth          * errors may result in EINVAL, however, so the user should check the
431c216e5adSMichael Roth          * number * of filesystems returned here against those returned by the
432c216e5adSMichael Roth          * thaw operation to determine whether everything completed
433c216e5adSMichael Roth          * successfully
434c216e5adSMichael Roth          */
435c216e5adSMichael Roth         ret = ioctl(fd, FIFREEZE);
436c216e5adSMichael Roth         if (ret < 0 && errno != EOPNOTSUPP) {
437c216e5adSMichael Roth             sprintf(err_msg, "failed to freeze %s, %s", mount->dirname, strerror(errno));
438c216e5adSMichael Roth             error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
439c216e5adSMichael Roth             close(fd);
440c216e5adSMichael Roth             goto error;
441c216e5adSMichael Roth         }
442c216e5adSMichael Roth         close(fd);
443c216e5adSMichael Roth 
444c216e5adSMichael Roth         i++;
445c216e5adSMichael Roth     }
446c216e5adSMichael Roth 
447c216e5adSMichael Roth     guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_FROZEN;
448c216e5adSMichael Roth     return i;
449c216e5adSMichael Roth 
450c216e5adSMichael Roth error:
451c216e5adSMichael Roth     if (i > 0) {
452c216e5adSMichael Roth         qmp_guest_fsfreeze_thaw(NULL);
453c216e5adSMichael Roth     }
454c216e5adSMichael Roth     return 0;
455c216e5adSMichael Roth }
456c216e5adSMichael Roth 
457c216e5adSMichael Roth /*
458c216e5adSMichael Roth  * Walk list of frozen file systems in the guest, and thaw them.
459c216e5adSMichael Roth  */
460c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err)
461c216e5adSMichael Roth {
462c216e5adSMichael Roth     int ret;
463c216e5adSMichael Roth     GuestFsfreezeMount *mount, *temp;
464c216e5adSMichael Roth     int fd, i = 0;
465c216e5adSMichael Roth     bool has_error = false;
466c216e5adSMichael Roth 
467c216e5adSMichael Roth     QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
468c216e5adSMichael Roth         fd = qemu_open(mount->dirname, O_RDONLY);
469c216e5adSMichael Roth         if (fd == -1) {
470c216e5adSMichael Roth             has_error = true;
471c216e5adSMichael Roth             continue;
472c216e5adSMichael Roth         }
473c216e5adSMichael Roth         ret = ioctl(fd, FITHAW);
474c216e5adSMichael Roth         if (ret < 0 && errno != EOPNOTSUPP && errno != EINVAL) {
475c216e5adSMichael Roth             has_error = true;
476c216e5adSMichael Roth             close(fd);
477c216e5adSMichael Roth             continue;
478c216e5adSMichael Roth         }
479c216e5adSMichael Roth         close(fd);
480c216e5adSMichael Roth         i++;
481c216e5adSMichael Roth     }
482c216e5adSMichael Roth 
483c216e5adSMichael Roth     if (has_error) {
484c216e5adSMichael Roth         guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_ERROR;
485c216e5adSMichael Roth     } else {
486c216e5adSMichael Roth         guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
487c216e5adSMichael Roth     }
488c216e5adSMichael Roth     enable_logging();
489c216e5adSMichael Roth     return i;
490c216e5adSMichael Roth }
491c216e5adSMichael Roth 
492c216e5adSMichael Roth static void guest_fsfreeze_init(void)
493c216e5adSMichael Roth {
494c216e5adSMichael Roth     guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
495c216e5adSMichael Roth     QTAILQ_INIT(&guest_fsfreeze_state.mount_list);
496c216e5adSMichael Roth }
497c216e5adSMichael Roth 
498c216e5adSMichael Roth static void guest_fsfreeze_cleanup(void)
499c216e5adSMichael Roth {
500c216e5adSMichael Roth     int64_t ret;
501c216e5adSMichael Roth     Error *err = NULL;
502c216e5adSMichael Roth 
503c216e5adSMichael Roth     if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
504c216e5adSMichael Roth         ret = qmp_guest_fsfreeze_thaw(&err);
505c216e5adSMichael Roth         if (ret < 0 || err) {
506c216e5adSMichael Roth             slog("failed to clean up frozen filesystems");
507c216e5adSMichael Roth         }
508c216e5adSMichael Roth     }
509c216e5adSMichael Roth }
510c216e5adSMichael Roth #else
511c216e5adSMichael Roth /*
512c216e5adSMichael Roth  * Return status of freeze/thaw
513c216e5adSMichael Roth  */
514c216e5adSMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
515c216e5adSMichael Roth {
516c216e5adSMichael Roth     error_set(err, QERR_UNSUPPORTED);
517c216e5adSMichael Roth 
518c216e5adSMichael Roth     return 0;
519c216e5adSMichael Roth }
520c216e5adSMichael Roth 
521c216e5adSMichael Roth /*
522c216e5adSMichael Roth  * Walk list of mounted file systems in the guest, and freeze the ones which
523c216e5adSMichael Roth  * are real local file systems.
524c216e5adSMichael Roth  */
525c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err)
526c216e5adSMichael Roth {
527c216e5adSMichael Roth     error_set(err, QERR_UNSUPPORTED);
528c216e5adSMichael Roth 
529c216e5adSMichael Roth     return 0;
530c216e5adSMichael Roth }
531c216e5adSMichael Roth 
532c216e5adSMichael Roth /*
533c216e5adSMichael Roth  * Walk list of frozen file systems in the guest, and thaw them.
534c216e5adSMichael Roth  */
535c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err)
536c216e5adSMichael Roth {
537c216e5adSMichael Roth     error_set(err, QERR_UNSUPPORTED);
538c216e5adSMichael Roth 
539c216e5adSMichael Roth     return 0;
540c216e5adSMichael Roth }
541c216e5adSMichael Roth #endif
542c216e5adSMichael Roth 
54311d0f125SLuiz Capitulino #define LINUX_SYS_STATE_FILE "/sys/power/state"
54411d0f125SLuiz Capitulino #define SUSPEND_SUPPORTED 0
54511d0f125SLuiz Capitulino #define SUSPEND_NOT_SUPPORTED 1
54611d0f125SLuiz Capitulino 
54711d0f125SLuiz Capitulino /**
54811d0f125SLuiz Capitulino  * This function forks twice and the information about the mode support
54911d0f125SLuiz Capitulino  * status is passed to the qemu-ga process via a pipe.
55011d0f125SLuiz Capitulino  *
55111d0f125SLuiz Capitulino  * This approach allows us to keep the way we reap terminated children
55211d0f125SLuiz Capitulino  * in qemu-ga quite simple.
55311d0f125SLuiz Capitulino  */
55411d0f125SLuiz Capitulino static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
55511d0f125SLuiz Capitulino                                const char *sysfile_str, Error **err)
55611d0f125SLuiz Capitulino {
55711d0f125SLuiz Capitulino     pid_t pid;
55811d0f125SLuiz Capitulino     ssize_t ret;
55911d0f125SLuiz Capitulino     char *pmutils_path;
56011d0f125SLuiz Capitulino     int status, pipefds[2];
56111d0f125SLuiz Capitulino 
56211d0f125SLuiz Capitulino     if (pipe(pipefds) < 0) {
56311d0f125SLuiz Capitulino         error_set(err, QERR_UNDEFINED_ERROR);
56411d0f125SLuiz Capitulino         return;
56511d0f125SLuiz Capitulino     }
56611d0f125SLuiz Capitulino 
56711d0f125SLuiz Capitulino     pmutils_path = g_find_program_in_path(pmutils_bin);
56811d0f125SLuiz Capitulino 
56911d0f125SLuiz Capitulino     pid = fork();
57011d0f125SLuiz Capitulino     if (!pid) {
57111d0f125SLuiz Capitulino         struct sigaction act;
57211d0f125SLuiz Capitulino 
57311d0f125SLuiz Capitulino         memset(&act, 0, sizeof(act));
57411d0f125SLuiz Capitulino         act.sa_handler = SIG_DFL;
57511d0f125SLuiz Capitulino         sigaction(SIGCHLD, &act, NULL);
57611d0f125SLuiz Capitulino 
57711d0f125SLuiz Capitulino         setsid();
57811d0f125SLuiz Capitulino         close(pipefds[0]);
57911d0f125SLuiz Capitulino         reopen_fd_to_null(0);
58011d0f125SLuiz Capitulino         reopen_fd_to_null(1);
58111d0f125SLuiz Capitulino         reopen_fd_to_null(2);
58211d0f125SLuiz Capitulino 
58311d0f125SLuiz Capitulino         pid = fork();
58411d0f125SLuiz Capitulino         if (!pid) {
58511d0f125SLuiz Capitulino             int fd;
58611d0f125SLuiz Capitulino             char buf[32]; /* hopefully big enough */
58711d0f125SLuiz Capitulino 
58811d0f125SLuiz Capitulino             if (pmutils_path) {
58911d0f125SLuiz Capitulino                 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
59011d0f125SLuiz Capitulino             }
59111d0f125SLuiz Capitulino 
59211d0f125SLuiz Capitulino             /*
59311d0f125SLuiz Capitulino              * If we get here either pm-utils is not installed or execle() has
59411d0f125SLuiz Capitulino              * failed. Let's try the manual method if the caller wants it.
59511d0f125SLuiz Capitulino              */
59611d0f125SLuiz Capitulino 
59711d0f125SLuiz Capitulino             if (!sysfile_str) {
59811d0f125SLuiz Capitulino                 _exit(SUSPEND_NOT_SUPPORTED);
59911d0f125SLuiz Capitulino             }
60011d0f125SLuiz Capitulino 
60111d0f125SLuiz Capitulino             fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
60211d0f125SLuiz Capitulino             if (fd < 0) {
60311d0f125SLuiz Capitulino                 _exit(SUSPEND_NOT_SUPPORTED);
60411d0f125SLuiz Capitulino             }
60511d0f125SLuiz Capitulino 
60611d0f125SLuiz Capitulino             ret = read(fd, buf, sizeof(buf)-1);
60711d0f125SLuiz Capitulino             if (ret <= 0) {
60811d0f125SLuiz Capitulino                 _exit(SUSPEND_NOT_SUPPORTED);
60911d0f125SLuiz Capitulino             }
61011d0f125SLuiz Capitulino             buf[ret] = '\0';
61111d0f125SLuiz Capitulino 
61211d0f125SLuiz Capitulino             if (strstr(buf, sysfile_str)) {
61311d0f125SLuiz Capitulino                 _exit(SUSPEND_SUPPORTED);
61411d0f125SLuiz Capitulino             }
61511d0f125SLuiz Capitulino 
61611d0f125SLuiz Capitulino             _exit(SUSPEND_NOT_SUPPORTED);
61711d0f125SLuiz Capitulino         }
61811d0f125SLuiz Capitulino 
61911d0f125SLuiz Capitulino         if (pid > 0) {
62011d0f125SLuiz Capitulino             wait(&status);
62111d0f125SLuiz Capitulino         } else {
62211d0f125SLuiz Capitulino             status = SUSPEND_NOT_SUPPORTED;
62311d0f125SLuiz Capitulino         }
62411d0f125SLuiz Capitulino 
62511d0f125SLuiz Capitulino         ret = write(pipefds[1], &status, sizeof(status));
62611d0f125SLuiz Capitulino         if (ret != sizeof(status)) {
62711d0f125SLuiz Capitulino             _exit(EXIT_FAILURE);
62811d0f125SLuiz Capitulino         }
62911d0f125SLuiz Capitulino 
63011d0f125SLuiz Capitulino         _exit(EXIT_SUCCESS);
63111d0f125SLuiz Capitulino     }
63211d0f125SLuiz Capitulino 
63311d0f125SLuiz Capitulino     close(pipefds[1]);
63411d0f125SLuiz Capitulino     g_free(pmutils_path);
63511d0f125SLuiz Capitulino 
63611d0f125SLuiz Capitulino     if (pid < 0) {
63711d0f125SLuiz Capitulino         error_set(err, QERR_UNDEFINED_ERROR);
63811d0f125SLuiz Capitulino         goto out;
63911d0f125SLuiz Capitulino     }
64011d0f125SLuiz Capitulino 
64111d0f125SLuiz Capitulino     ret = read(pipefds[0], &status, sizeof(status));
64211d0f125SLuiz Capitulino     if (ret == sizeof(status) && WIFEXITED(status) &&
64311d0f125SLuiz Capitulino         WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
64411d0f125SLuiz Capitulino             goto out;
64511d0f125SLuiz Capitulino     }
64611d0f125SLuiz Capitulino 
64711d0f125SLuiz Capitulino     error_set(err, QERR_UNSUPPORTED);
64811d0f125SLuiz Capitulino 
64911d0f125SLuiz Capitulino out:
65011d0f125SLuiz Capitulino     close(pipefds[0]);
65111d0f125SLuiz Capitulino }
65211d0f125SLuiz Capitulino 
65311d0f125SLuiz Capitulino static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
65411d0f125SLuiz Capitulino                           Error **err)
65511d0f125SLuiz Capitulino {
65611d0f125SLuiz Capitulino     pid_t pid;
65711d0f125SLuiz Capitulino     char *pmutils_path;
65811d0f125SLuiz Capitulino 
65911d0f125SLuiz Capitulino     pmutils_path = g_find_program_in_path(pmutils_bin);
66011d0f125SLuiz Capitulino 
66111d0f125SLuiz Capitulino     pid = fork();
66211d0f125SLuiz Capitulino     if (pid == 0) {
66311d0f125SLuiz Capitulino         /* child */
66411d0f125SLuiz Capitulino         int fd;
66511d0f125SLuiz Capitulino 
66611d0f125SLuiz Capitulino         setsid();
66711d0f125SLuiz Capitulino         reopen_fd_to_null(0);
66811d0f125SLuiz Capitulino         reopen_fd_to_null(1);
66911d0f125SLuiz Capitulino         reopen_fd_to_null(2);
67011d0f125SLuiz Capitulino 
67111d0f125SLuiz Capitulino         if (pmutils_path) {
67211d0f125SLuiz Capitulino             execle(pmutils_path, pmutils_bin, NULL, environ);
67311d0f125SLuiz Capitulino         }
67411d0f125SLuiz Capitulino 
67511d0f125SLuiz Capitulino         /*
67611d0f125SLuiz Capitulino          * If we get here either pm-utils is not installed or execle() has
67711d0f125SLuiz Capitulino          * failed. Let's try the manual method if the caller wants it.
67811d0f125SLuiz Capitulino          */
67911d0f125SLuiz Capitulino 
68011d0f125SLuiz Capitulino         if (!sysfile_str) {
68111d0f125SLuiz Capitulino             _exit(EXIT_FAILURE);
68211d0f125SLuiz Capitulino         }
68311d0f125SLuiz Capitulino 
68411d0f125SLuiz Capitulino         fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
68511d0f125SLuiz Capitulino         if (fd < 0) {
68611d0f125SLuiz Capitulino             _exit(EXIT_FAILURE);
68711d0f125SLuiz Capitulino         }
68811d0f125SLuiz Capitulino 
68911d0f125SLuiz Capitulino         if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
69011d0f125SLuiz Capitulino             _exit(EXIT_FAILURE);
69111d0f125SLuiz Capitulino         }
69211d0f125SLuiz Capitulino 
69311d0f125SLuiz Capitulino         _exit(EXIT_SUCCESS);
69411d0f125SLuiz Capitulino     }
69511d0f125SLuiz Capitulino 
69611d0f125SLuiz Capitulino     g_free(pmutils_path);
69711d0f125SLuiz Capitulino 
69811d0f125SLuiz Capitulino     if (pid < 0) {
69911d0f125SLuiz Capitulino         error_set(err, QERR_UNDEFINED_ERROR);
70011d0f125SLuiz Capitulino         return;
70111d0f125SLuiz Capitulino     }
70211d0f125SLuiz Capitulino }
70311d0f125SLuiz Capitulino 
70411d0f125SLuiz Capitulino void qmp_guest_suspend_disk(Error **err)
70511d0f125SLuiz Capitulino {
70611d0f125SLuiz Capitulino     bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
70711d0f125SLuiz Capitulino     if (error_is_set(err)) {
70811d0f125SLuiz Capitulino         return;
70911d0f125SLuiz Capitulino     }
71011d0f125SLuiz Capitulino 
71111d0f125SLuiz Capitulino     guest_suspend("pm-hibernate", "disk", err);
71211d0f125SLuiz Capitulino }
71311d0f125SLuiz Capitulino 
714fbf42210SLuiz Capitulino void qmp_guest_suspend_ram(Error **err)
715fbf42210SLuiz Capitulino {
716fbf42210SLuiz Capitulino     bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
717fbf42210SLuiz Capitulino     if (error_is_set(err)) {
718fbf42210SLuiz Capitulino         return;
719fbf42210SLuiz Capitulino     }
720fbf42210SLuiz Capitulino 
721fbf42210SLuiz Capitulino     guest_suspend("pm-suspend", "mem", err);
722fbf42210SLuiz Capitulino }
723fbf42210SLuiz Capitulino 
72495f4f404SLuiz Capitulino void qmp_guest_suspend_hybrid(Error **err)
72595f4f404SLuiz Capitulino {
72695f4f404SLuiz Capitulino     bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
72795f4f404SLuiz Capitulino     if (error_is_set(err)) {
72895f4f404SLuiz Capitulino         return;
72995f4f404SLuiz Capitulino     }
73095f4f404SLuiz Capitulino 
73195f4f404SLuiz Capitulino     guest_suspend("pm-suspend-hybrid", NULL, err);
73295f4f404SLuiz Capitulino }
73395f4f404SLuiz Capitulino 
734*3424fc9fSMichal Privoznik static GuestNetworkInterfaceList *
735*3424fc9fSMichal Privoznik guest_find_interface(GuestNetworkInterfaceList *head,
736*3424fc9fSMichal Privoznik                      const char *name)
737*3424fc9fSMichal Privoznik {
738*3424fc9fSMichal Privoznik     for (; head; head = head->next) {
739*3424fc9fSMichal Privoznik         if (strcmp(head->value->name, name) == 0) {
740*3424fc9fSMichal Privoznik             break;
741*3424fc9fSMichal Privoznik         }
742*3424fc9fSMichal Privoznik     }
743*3424fc9fSMichal Privoznik 
744*3424fc9fSMichal Privoznik     return head;
745*3424fc9fSMichal Privoznik }
746*3424fc9fSMichal Privoznik 
747*3424fc9fSMichal Privoznik /*
748*3424fc9fSMichal Privoznik  * Build information about guest interfaces
749*3424fc9fSMichal Privoznik  */
750*3424fc9fSMichal Privoznik GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
751*3424fc9fSMichal Privoznik {
752*3424fc9fSMichal Privoznik     GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
753*3424fc9fSMichal Privoznik     struct ifaddrs *ifap, *ifa;
754*3424fc9fSMichal Privoznik     char err_msg[512];
755*3424fc9fSMichal Privoznik 
756*3424fc9fSMichal Privoznik     if (getifaddrs(&ifap) < 0) {
757*3424fc9fSMichal Privoznik         snprintf(err_msg, sizeof(err_msg),
758*3424fc9fSMichal Privoznik                  "getifaddrs failed: %s", strerror(errno));
759*3424fc9fSMichal Privoznik         error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
760*3424fc9fSMichal Privoznik         goto error;
761*3424fc9fSMichal Privoznik     }
762*3424fc9fSMichal Privoznik 
763*3424fc9fSMichal Privoznik     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
764*3424fc9fSMichal Privoznik         GuestNetworkInterfaceList *info;
765*3424fc9fSMichal Privoznik         GuestIpAddressList **address_list = NULL, *address_item = NULL;
766*3424fc9fSMichal Privoznik         char addr4[INET_ADDRSTRLEN];
767*3424fc9fSMichal Privoznik         char addr6[INET6_ADDRSTRLEN];
768*3424fc9fSMichal Privoznik         int sock;
769*3424fc9fSMichal Privoznik         struct ifreq ifr;
770*3424fc9fSMichal Privoznik         unsigned char *mac_addr;
771*3424fc9fSMichal Privoznik         void *p;
772*3424fc9fSMichal Privoznik 
773*3424fc9fSMichal Privoznik         g_debug("Processing %s interface", ifa->ifa_name);
774*3424fc9fSMichal Privoznik 
775*3424fc9fSMichal Privoznik         info = guest_find_interface(head, ifa->ifa_name);
776*3424fc9fSMichal Privoznik 
777*3424fc9fSMichal Privoznik         if (!info) {
778*3424fc9fSMichal Privoznik             info = g_malloc0(sizeof(*info));
779*3424fc9fSMichal Privoznik             info->value = g_malloc0(sizeof(*info->value));
780*3424fc9fSMichal Privoznik             info->value->name = g_strdup(ifa->ifa_name);
781*3424fc9fSMichal Privoznik 
782*3424fc9fSMichal Privoznik             if (!cur_item) {
783*3424fc9fSMichal Privoznik                 head = cur_item = info;
784*3424fc9fSMichal Privoznik             } else {
785*3424fc9fSMichal Privoznik                 cur_item->next = info;
786*3424fc9fSMichal Privoznik                 cur_item = info;
787*3424fc9fSMichal Privoznik             }
788*3424fc9fSMichal Privoznik         }
789*3424fc9fSMichal Privoznik 
790*3424fc9fSMichal Privoznik         if (!info->value->has_hardware_address &&
791*3424fc9fSMichal Privoznik             ifa->ifa_flags & SIOCGIFHWADDR) {
792*3424fc9fSMichal Privoznik             /* we haven't obtained HW address yet */
793*3424fc9fSMichal Privoznik             sock = socket(PF_INET, SOCK_STREAM, 0);
794*3424fc9fSMichal Privoznik             if (sock == -1) {
795*3424fc9fSMichal Privoznik                 snprintf(err_msg, sizeof(err_msg),
796*3424fc9fSMichal Privoznik                          "failed to create socket: %s", strerror(errno));
797*3424fc9fSMichal Privoznik                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
798*3424fc9fSMichal Privoznik                 goto error;
799*3424fc9fSMichal Privoznik             }
800*3424fc9fSMichal Privoznik 
801*3424fc9fSMichal Privoznik             memset(&ifr, 0, sizeof(ifr));
802*3424fc9fSMichal Privoznik             strncpy(ifr.ifr_name,  info->value->name, IF_NAMESIZE);
803*3424fc9fSMichal Privoznik             if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
804*3424fc9fSMichal Privoznik                 snprintf(err_msg, sizeof(err_msg),
805*3424fc9fSMichal Privoznik                          "failed to get MAC addres of %s: %s",
806*3424fc9fSMichal Privoznik                          ifa->ifa_name,
807*3424fc9fSMichal Privoznik                          strerror(errno));
808*3424fc9fSMichal Privoznik                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
809*3424fc9fSMichal Privoznik                 goto error;
810*3424fc9fSMichal Privoznik             }
811*3424fc9fSMichal Privoznik 
812*3424fc9fSMichal Privoznik             mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
813*3424fc9fSMichal Privoznik 
814*3424fc9fSMichal Privoznik             if (asprintf(&info->value->hardware_address,
815*3424fc9fSMichal Privoznik                          "%02x:%02x:%02x:%02x:%02x:%02x",
816*3424fc9fSMichal Privoznik                          (int) mac_addr[0], (int) mac_addr[1],
817*3424fc9fSMichal Privoznik                          (int) mac_addr[2], (int) mac_addr[3],
818*3424fc9fSMichal Privoznik                          (int) mac_addr[4], (int) mac_addr[5]) == -1) {
819*3424fc9fSMichal Privoznik                 snprintf(err_msg, sizeof(err_msg),
820*3424fc9fSMichal Privoznik                          "failed to format MAC: %s", strerror(errno));
821*3424fc9fSMichal Privoznik                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
822*3424fc9fSMichal Privoznik                 goto error;
823*3424fc9fSMichal Privoznik             }
824*3424fc9fSMichal Privoznik 
825*3424fc9fSMichal Privoznik             info->value->has_hardware_address = true;
826*3424fc9fSMichal Privoznik             close(sock);
827*3424fc9fSMichal Privoznik         }
828*3424fc9fSMichal Privoznik 
829*3424fc9fSMichal Privoznik         if (ifa->ifa_addr &&
830*3424fc9fSMichal Privoznik             ifa->ifa_addr->sa_family == AF_INET) {
831*3424fc9fSMichal Privoznik             /* interface with IPv4 address */
832*3424fc9fSMichal Privoznik             address_item = g_malloc0(sizeof(*address_item));
833*3424fc9fSMichal Privoznik             address_item->value = g_malloc0(sizeof(*address_item->value));
834*3424fc9fSMichal Privoznik             p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
835*3424fc9fSMichal Privoznik             if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
836*3424fc9fSMichal Privoznik                 snprintf(err_msg, sizeof(err_msg),
837*3424fc9fSMichal Privoznik                          "inet_ntop failed : %s", strerror(errno));
838*3424fc9fSMichal Privoznik                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
839*3424fc9fSMichal Privoznik                 goto error;
840*3424fc9fSMichal Privoznik             }
841*3424fc9fSMichal Privoznik 
842*3424fc9fSMichal Privoznik             address_item->value->ip_address = g_strdup(addr4);
843*3424fc9fSMichal Privoznik             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
844*3424fc9fSMichal Privoznik 
845*3424fc9fSMichal Privoznik             if (ifa->ifa_netmask) {
846*3424fc9fSMichal Privoznik                 /* Count the number of set bits in netmask.
847*3424fc9fSMichal Privoznik                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
848*3424fc9fSMichal Privoznik                 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
849*3424fc9fSMichal Privoznik                 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
850*3424fc9fSMichal Privoznik             }
851*3424fc9fSMichal Privoznik         } else if (ifa->ifa_addr &&
852*3424fc9fSMichal Privoznik                    ifa->ifa_addr->sa_family == AF_INET6) {
853*3424fc9fSMichal Privoznik             /* interface with IPv6 address */
854*3424fc9fSMichal Privoznik             address_item = g_malloc0(sizeof(*address_item));
855*3424fc9fSMichal Privoznik             address_item->value = g_malloc0(sizeof(*address_item->value));
856*3424fc9fSMichal Privoznik             p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
857*3424fc9fSMichal Privoznik             if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
858*3424fc9fSMichal Privoznik                 snprintf(err_msg, sizeof(err_msg),
859*3424fc9fSMichal Privoznik                          "inet_ntop failed : %s", strerror(errno));
860*3424fc9fSMichal Privoznik                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
861*3424fc9fSMichal Privoznik                 goto error;
862*3424fc9fSMichal Privoznik             }
863*3424fc9fSMichal Privoznik 
864*3424fc9fSMichal Privoznik             address_item->value->ip_address = g_strdup(addr6);
865*3424fc9fSMichal Privoznik             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
866*3424fc9fSMichal Privoznik 
867*3424fc9fSMichal Privoznik             if (ifa->ifa_netmask) {
868*3424fc9fSMichal Privoznik                 /* Count the number of set bits in netmask.
869*3424fc9fSMichal Privoznik                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
870*3424fc9fSMichal Privoznik                 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
871*3424fc9fSMichal Privoznik                 address_item->value->prefix =
872*3424fc9fSMichal Privoznik                     ctpop32(((uint32_t *) p)[0]) +
873*3424fc9fSMichal Privoznik                     ctpop32(((uint32_t *) p)[1]) +
874*3424fc9fSMichal Privoznik                     ctpop32(((uint32_t *) p)[2]) +
875*3424fc9fSMichal Privoznik                     ctpop32(((uint32_t *) p)[3]);
876*3424fc9fSMichal Privoznik             }
877*3424fc9fSMichal Privoznik         }
878*3424fc9fSMichal Privoznik 
879*3424fc9fSMichal Privoznik         if (!address_item) {
880*3424fc9fSMichal Privoznik             continue;
881*3424fc9fSMichal Privoznik         }
882*3424fc9fSMichal Privoznik 
883*3424fc9fSMichal Privoznik         address_list = &info->value->ip_addresses;
884*3424fc9fSMichal Privoznik 
885*3424fc9fSMichal Privoznik         while (*address_list && (*address_list)->next) {
886*3424fc9fSMichal Privoznik             address_list = &(*address_list)->next;
887*3424fc9fSMichal Privoznik         }
888*3424fc9fSMichal Privoznik 
889*3424fc9fSMichal Privoznik         if (!*address_list) {
890*3424fc9fSMichal Privoznik             *address_list = address_item;
891*3424fc9fSMichal Privoznik         } else {
892*3424fc9fSMichal Privoznik             (*address_list)->next = address_item;
893*3424fc9fSMichal Privoznik         }
894*3424fc9fSMichal Privoznik 
895*3424fc9fSMichal Privoznik         info->value->has_ip_addresses = true;
896*3424fc9fSMichal Privoznik 
897*3424fc9fSMichal Privoznik 
898*3424fc9fSMichal Privoznik     }
899*3424fc9fSMichal Privoznik 
900*3424fc9fSMichal Privoznik     freeifaddrs(ifap);
901*3424fc9fSMichal Privoznik     return head;
902*3424fc9fSMichal Privoznik 
903*3424fc9fSMichal Privoznik error:
904*3424fc9fSMichal Privoznik     freeifaddrs(ifap);
905*3424fc9fSMichal Privoznik     qapi_free_GuestNetworkInterfaceList(head);
906*3424fc9fSMichal Privoznik     return NULL;
907*3424fc9fSMichal Privoznik }
908*3424fc9fSMichal Privoznik 
909c216e5adSMichael Roth /* register init/cleanup routines for stateful command groups */
910c216e5adSMichael Roth void ga_command_state_init(GAState *s, GACommandState *cs)
911c216e5adSMichael Roth {
912c216e5adSMichael Roth     ga_state = s;
913c216e5adSMichael Roth #if defined(CONFIG_FSFREEZE)
914c216e5adSMichael Roth     ga_command_state_add(cs, guest_fsfreeze_init, guest_fsfreeze_cleanup);
915c216e5adSMichael Roth #endif
916c216e5adSMichael Roth     ga_command_state_add(cs, guest_file_init, NULL);
917c216e5adSMichael Roth }
918