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> 83424fc9fSMichal 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 #include <sys/types.h> 16c216e5adSMichael Roth #include <sys/ioctl.h> 17c216e5adSMichael Roth #include "qga/guest-agent-core.h" 18c216e5adSMichael Roth #include "qga-qmp-commands.h" 19c216e5adSMichael Roth #include "qerror.h" 20c216e5adSMichael Roth #include "qemu-queue.h" 213424fc9fSMichal Privoznik #include "host-utils.h" 22c216e5adSMichael Roth 23e72c3f2eSMichael Roth #if defined(__linux__) 24e72c3f2eSMichael Roth #include <mntent.h> 25e72c3f2eSMichael Roth #include <linux/fs.h> 26e72c3f2eSMichael Roth #include <ifaddrs.h> 27e72c3f2eSMichael Roth #include <arpa/inet.h> 28e72c3f2eSMichael Roth #include <sys/socket.h> 29e72c3f2eSMichael Roth #include <net/if.h> 30e72c3f2eSMichael Roth #include <sys/wait.h> 31e72c3f2eSMichael Roth 32e72c3f2eSMichael Roth #if defined(__linux__) && defined(FIFREEZE) 33e72c3f2eSMichael Roth #define CONFIG_FSFREEZE 34e72c3f2eSMichael Roth #endif 35e72c3f2eSMichael Roth #endif 36e72c3f2eSMichael Roth 37e72c3f2eSMichael Roth #if defined(__linux__) 38e72c3f2eSMichael Roth /* TODO: use this in place of all post-fork() fclose(std*) callers */ 3911d0f125SLuiz Capitulino static void reopen_fd_to_null(int fd) 4011d0f125SLuiz Capitulino { 4111d0f125SLuiz Capitulino int nullfd; 4211d0f125SLuiz Capitulino 4311d0f125SLuiz Capitulino nullfd = open("/dev/null", O_RDWR); 4411d0f125SLuiz Capitulino if (nullfd < 0) { 4511d0f125SLuiz Capitulino return; 4611d0f125SLuiz Capitulino } 4711d0f125SLuiz Capitulino 4811d0f125SLuiz Capitulino dup2(nullfd, fd); 4911d0f125SLuiz Capitulino 5011d0f125SLuiz Capitulino if (nullfd != fd) { 5111d0f125SLuiz Capitulino close(nullfd); 5211d0f125SLuiz Capitulino } 5311d0f125SLuiz Capitulino } 54e72c3f2eSMichael Roth #endif /* defined(__linux__) */ 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 314e72c3f2eSMichael Roth /* linux-specific implementations. avoid this if at all possible. */ 315e72c3f2eSMichael Roth #if defined(__linux__) 316e72c3f2eSMichael Roth 317c216e5adSMichael Roth #if defined(CONFIG_FSFREEZE) 318e72c3f2eSMichael Roth 319c216e5adSMichael Roth static void disable_logging(void) 320c216e5adSMichael Roth { 321c216e5adSMichael Roth ga_disable_logging(ga_state); 322c216e5adSMichael Roth } 323c216e5adSMichael Roth 324c216e5adSMichael Roth static void enable_logging(void) 325c216e5adSMichael Roth { 326c216e5adSMichael Roth ga_enable_logging(ga_state); 327c216e5adSMichael Roth } 328c216e5adSMichael Roth 329c216e5adSMichael Roth typedef struct GuestFsfreezeMount { 330c216e5adSMichael Roth char *dirname; 331c216e5adSMichael Roth char *devtype; 332c216e5adSMichael Roth QTAILQ_ENTRY(GuestFsfreezeMount) next; 333c216e5adSMichael Roth } GuestFsfreezeMount; 334c216e5adSMichael Roth 335c216e5adSMichael Roth struct { 336c216e5adSMichael Roth GuestFsfreezeStatus status; 337c216e5adSMichael Roth QTAILQ_HEAD(, GuestFsfreezeMount) mount_list; 338c216e5adSMichael Roth } guest_fsfreeze_state; 339c216e5adSMichael Roth 340c216e5adSMichael Roth /* 341c216e5adSMichael Roth * Walk the mount table and build a list of local file systems 342c216e5adSMichael Roth */ 343c216e5adSMichael Roth static int guest_fsfreeze_build_mount_list(void) 344c216e5adSMichael Roth { 345c216e5adSMichael Roth struct mntent *ment; 346c216e5adSMichael Roth GuestFsfreezeMount *mount, *temp; 347c216e5adSMichael Roth char const *mtab = MOUNTED; 348c216e5adSMichael Roth FILE *fp; 349c216e5adSMichael Roth 350c216e5adSMichael Roth QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) { 351c216e5adSMichael Roth QTAILQ_REMOVE(&guest_fsfreeze_state.mount_list, mount, next); 352c216e5adSMichael Roth g_free(mount->dirname); 353c216e5adSMichael Roth g_free(mount->devtype); 354c216e5adSMichael Roth g_free(mount); 355c216e5adSMichael Roth } 356c216e5adSMichael Roth 357c216e5adSMichael Roth fp = setmntent(mtab, "r"); 358c216e5adSMichael Roth if (!fp) { 359c216e5adSMichael Roth g_warning("fsfreeze: unable to read mtab"); 360c216e5adSMichael Roth return -1; 361c216e5adSMichael Roth } 362c216e5adSMichael Roth 363c216e5adSMichael Roth while ((ment = getmntent(fp))) { 364c216e5adSMichael Roth /* 365c216e5adSMichael Roth * An entry which device name doesn't start with a '/' is 366c216e5adSMichael Roth * either a dummy file system or a network file system. 367c216e5adSMichael Roth * Add special handling for smbfs and cifs as is done by 368c216e5adSMichael Roth * coreutils as well. 369c216e5adSMichael Roth */ 370c216e5adSMichael Roth if ((ment->mnt_fsname[0] != '/') || 371c216e5adSMichael Roth (strcmp(ment->mnt_type, "smbfs") == 0) || 372c216e5adSMichael Roth (strcmp(ment->mnt_type, "cifs") == 0)) { 373c216e5adSMichael Roth continue; 374c216e5adSMichael Roth } 375c216e5adSMichael Roth 376c216e5adSMichael Roth mount = g_malloc0(sizeof(GuestFsfreezeMount)); 377c216e5adSMichael Roth mount->dirname = g_strdup(ment->mnt_dir); 378c216e5adSMichael Roth mount->devtype = g_strdup(ment->mnt_type); 379c216e5adSMichael Roth 380c216e5adSMichael Roth QTAILQ_INSERT_TAIL(&guest_fsfreeze_state.mount_list, mount, next); 381c216e5adSMichael Roth } 382c216e5adSMichael Roth 383c216e5adSMichael Roth endmntent(fp); 384c216e5adSMichael Roth 385c216e5adSMichael Roth return 0; 386c216e5adSMichael Roth } 387c216e5adSMichael Roth 388c216e5adSMichael Roth /* 389c216e5adSMichael Roth * Return status of freeze/thaw 390c216e5adSMichael Roth */ 391c216e5adSMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 392c216e5adSMichael Roth { 393c216e5adSMichael Roth return guest_fsfreeze_state.status; 394c216e5adSMichael Roth } 395c216e5adSMichael Roth 396c216e5adSMichael Roth /* 397c216e5adSMichael Roth * Walk list of mounted file systems in the guest, and freeze the ones which 398c216e5adSMichael Roth * are real local file systems. 399c216e5adSMichael Roth */ 400c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 401c216e5adSMichael Roth { 402c216e5adSMichael Roth int ret = 0, i = 0; 403c216e5adSMichael Roth struct GuestFsfreezeMount *mount, *temp; 404c216e5adSMichael Roth int fd; 405c216e5adSMichael Roth char err_msg[512]; 406c216e5adSMichael Roth 407c216e5adSMichael Roth slog("guest-fsfreeze called"); 408c216e5adSMichael Roth 409c216e5adSMichael Roth if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) { 410c216e5adSMichael Roth return 0; 411c216e5adSMichael Roth } 412c216e5adSMichael Roth 413c216e5adSMichael Roth ret = guest_fsfreeze_build_mount_list(); 414c216e5adSMichael Roth if (ret < 0) { 415c216e5adSMichael Roth return ret; 416c216e5adSMichael Roth } 417c216e5adSMichael Roth 418c216e5adSMichael Roth /* cannot risk guest agent blocking itself on a write in this state */ 419c216e5adSMichael Roth disable_logging(); 420c216e5adSMichael Roth 421c216e5adSMichael Roth QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) { 422c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 423c216e5adSMichael Roth if (fd == -1) { 424c216e5adSMichael Roth sprintf(err_msg, "failed to open %s, %s", mount->dirname, strerror(errno)); 425c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 426c216e5adSMichael Roth goto error; 427c216e5adSMichael Roth } 428c216e5adSMichael Roth 429c216e5adSMichael Roth /* we try to cull filesytems we know won't work in advance, but other 430c216e5adSMichael Roth * filesytems may not implement fsfreeze for less obvious reasons. 431c216e5adSMichael Roth * these will report EOPNOTSUPP, so we simply ignore them. when 432c216e5adSMichael Roth * thawing, these filesystems will return an EINVAL instead, due to 433c216e5adSMichael Roth * not being in a frozen state. Other filesystem-specific 434c216e5adSMichael Roth * errors may result in EINVAL, however, so the user should check the 435c216e5adSMichael Roth * number * of filesystems returned here against those returned by the 436c216e5adSMichael Roth * thaw operation to determine whether everything completed 437c216e5adSMichael Roth * successfully 438c216e5adSMichael Roth */ 439c216e5adSMichael Roth ret = ioctl(fd, FIFREEZE); 440c216e5adSMichael Roth if (ret < 0 && errno != EOPNOTSUPP) { 441c216e5adSMichael Roth sprintf(err_msg, "failed to freeze %s, %s", mount->dirname, strerror(errno)); 442c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 443c216e5adSMichael Roth close(fd); 444c216e5adSMichael Roth goto error; 445c216e5adSMichael Roth } 446c216e5adSMichael Roth close(fd); 447c216e5adSMichael Roth 448c216e5adSMichael Roth i++; 449c216e5adSMichael Roth } 450c216e5adSMichael Roth 451c216e5adSMichael Roth guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_FROZEN; 452c216e5adSMichael Roth return i; 453c216e5adSMichael Roth 454c216e5adSMichael Roth error: 455c216e5adSMichael Roth if (i > 0) { 456c216e5adSMichael Roth qmp_guest_fsfreeze_thaw(NULL); 457c216e5adSMichael Roth } 458c216e5adSMichael Roth return 0; 459c216e5adSMichael Roth } 460c216e5adSMichael Roth 461c216e5adSMichael Roth /* 462c216e5adSMichael Roth * Walk list of frozen file systems in the guest, and thaw them. 463c216e5adSMichael Roth */ 464c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 465c216e5adSMichael Roth { 466c216e5adSMichael Roth int ret; 467c216e5adSMichael Roth GuestFsfreezeMount *mount, *temp; 468c216e5adSMichael Roth int fd, i = 0; 469c216e5adSMichael Roth bool has_error = false; 470c216e5adSMichael Roth 471c216e5adSMichael Roth QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) { 472c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 473c216e5adSMichael Roth if (fd == -1) { 474c216e5adSMichael Roth has_error = true; 475c216e5adSMichael Roth continue; 476c216e5adSMichael Roth } 477c216e5adSMichael Roth ret = ioctl(fd, FITHAW); 478c216e5adSMichael Roth if (ret < 0 && errno != EOPNOTSUPP && errno != EINVAL) { 479c216e5adSMichael Roth has_error = true; 480c216e5adSMichael Roth close(fd); 481c216e5adSMichael Roth continue; 482c216e5adSMichael Roth } 483c216e5adSMichael Roth close(fd); 484c216e5adSMichael Roth i++; 485c216e5adSMichael Roth } 486c216e5adSMichael Roth 487c216e5adSMichael Roth if (has_error) { 488c216e5adSMichael Roth guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_ERROR; 489c216e5adSMichael Roth } else { 490c216e5adSMichael Roth guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED; 491c216e5adSMichael Roth } 492c216e5adSMichael Roth enable_logging(); 493c216e5adSMichael Roth return i; 494c216e5adSMichael Roth } 495c216e5adSMichael Roth 496c216e5adSMichael Roth static void guest_fsfreeze_init(void) 497c216e5adSMichael Roth { 498c216e5adSMichael Roth guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED; 499c216e5adSMichael Roth QTAILQ_INIT(&guest_fsfreeze_state.mount_list); 500c216e5adSMichael Roth } 501c216e5adSMichael Roth 502c216e5adSMichael Roth static void guest_fsfreeze_cleanup(void) 503c216e5adSMichael Roth { 504c216e5adSMichael Roth int64_t ret; 505c216e5adSMichael Roth Error *err = NULL; 506c216e5adSMichael Roth 507c216e5adSMichael Roth if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) { 508c216e5adSMichael Roth ret = qmp_guest_fsfreeze_thaw(&err); 509c216e5adSMichael Roth if (ret < 0 || err) { 510c216e5adSMichael Roth slog("failed to clean up frozen filesystems"); 511c216e5adSMichael Roth } 512c216e5adSMichael Roth } 513c216e5adSMichael Roth } 514e72c3f2eSMichael Roth #endif /* CONFIG_FSFREEZE */ 515c216e5adSMichael Roth 51611d0f125SLuiz Capitulino #define LINUX_SYS_STATE_FILE "/sys/power/state" 51711d0f125SLuiz Capitulino #define SUSPEND_SUPPORTED 0 51811d0f125SLuiz Capitulino #define SUSPEND_NOT_SUPPORTED 1 51911d0f125SLuiz Capitulino 52011d0f125SLuiz Capitulino /** 52111d0f125SLuiz Capitulino * This function forks twice and the information about the mode support 52211d0f125SLuiz Capitulino * status is passed to the qemu-ga process via a pipe. 52311d0f125SLuiz Capitulino * 52411d0f125SLuiz Capitulino * This approach allows us to keep the way we reap terminated children 52511d0f125SLuiz Capitulino * in qemu-ga quite simple. 52611d0f125SLuiz Capitulino */ 52711d0f125SLuiz Capitulino static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, 52811d0f125SLuiz Capitulino const char *sysfile_str, Error **err) 52911d0f125SLuiz Capitulino { 53011d0f125SLuiz Capitulino pid_t pid; 53111d0f125SLuiz Capitulino ssize_t ret; 53211d0f125SLuiz Capitulino char *pmutils_path; 53311d0f125SLuiz Capitulino int status, pipefds[2]; 53411d0f125SLuiz Capitulino 53511d0f125SLuiz Capitulino if (pipe(pipefds) < 0) { 53611d0f125SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 53711d0f125SLuiz Capitulino return; 53811d0f125SLuiz Capitulino } 53911d0f125SLuiz Capitulino 54011d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 54111d0f125SLuiz Capitulino 54211d0f125SLuiz Capitulino pid = fork(); 54311d0f125SLuiz Capitulino if (!pid) { 54411d0f125SLuiz Capitulino struct sigaction act; 54511d0f125SLuiz Capitulino 54611d0f125SLuiz Capitulino memset(&act, 0, sizeof(act)); 54711d0f125SLuiz Capitulino act.sa_handler = SIG_DFL; 54811d0f125SLuiz Capitulino sigaction(SIGCHLD, &act, NULL); 54911d0f125SLuiz Capitulino 55011d0f125SLuiz Capitulino setsid(); 55111d0f125SLuiz Capitulino close(pipefds[0]); 55211d0f125SLuiz Capitulino reopen_fd_to_null(0); 55311d0f125SLuiz Capitulino reopen_fd_to_null(1); 55411d0f125SLuiz Capitulino reopen_fd_to_null(2); 55511d0f125SLuiz Capitulino 55611d0f125SLuiz Capitulino pid = fork(); 55711d0f125SLuiz Capitulino if (!pid) { 55811d0f125SLuiz Capitulino int fd; 55911d0f125SLuiz Capitulino char buf[32]; /* hopefully big enough */ 56011d0f125SLuiz Capitulino 56111d0f125SLuiz Capitulino if (pmutils_path) { 56211d0f125SLuiz Capitulino execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ); 56311d0f125SLuiz Capitulino } 56411d0f125SLuiz Capitulino 56511d0f125SLuiz Capitulino /* 56611d0f125SLuiz Capitulino * If we get here either pm-utils is not installed or execle() has 56711d0f125SLuiz Capitulino * failed. Let's try the manual method if the caller wants it. 56811d0f125SLuiz Capitulino */ 56911d0f125SLuiz Capitulino 57011d0f125SLuiz Capitulino if (!sysfile_str) { 57111d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 57211d0f125SLuiz Capitulino } 57311d0f125SLuiz Capitulino 57411d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); 57511d0f125SLuiz Capitulino if (fd < 0) { 57611d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 57711d0f125SLuiz Capitulino } 57811d0f125SLuiz Capitulino 57911d0f125SLuiz Capitulino ret = read(fd, buf, sizeof(buf)-1); 58011d0f125SLuiz Capitulino if (ret <= 0) { 58111d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 58211d0f125SLuiz Capitulino } 58311d0f125SLuiz Capitulino buf[ret] = '\0'; 58411d0f125SLuiz Capitulino 58511d0f125SLuiz Capitulino if (strstr(buf, sysfile_str)) { 58611d0f125SLuiz Capitulino _exit(SUSPEND_SUPPORTED); 58711d0f125SLuiz Capitulino } 58811d0f125SLuiz Capitulino 58911d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 59011d0f125SLuiz Capitulino } 59111d0f125SLuiz Capitulino 59211d0f125SLuiz Capitulino if (pid > 0) { 59311d0f125SLuiz Capitulino wait(&status); 59411d0f125SLuiz Capitulino } else { 59511d0f125SLuiz Capitulino status = SUSPEND_NOT_SUPPORTED; 59611d0f125SLuiz Capitulino } 59711d0f125SLuiz Capitulino 59811d0f125SLuiz Capitulino ret = write(pipefds[1], &status, sizeof(status)); 59911d0f125SLuiz Capitulino if (ret != sizeof(status)) { 60011d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 60111d0f125SLuiz Capitulino } 60211d0f125SLuiz Capitulino 60311d0f125SLuiz Capitulino _exit(EXIT_SUCCESS); 60411d0f125SLuiz Capitulino } 60511d0f125SLuiz Capitulino 60611d0f125SLuiz Capitulino close(pipefds[1]); 60711d0f125SLuiz Capitulino g_free(pmutils_path); 60811d0f125SLuiz Capitulino 60911d0f125SLuiz Capitulino if (pid < 0) { 61011d0f125SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 61111d0f125SLuiz Capitulino goto out; 61211d0f125SLuiz Capitulino } 61311d0f125SLuiz Capitulino 61411d0f125SLuiz Capitulino ret = read(pipefds[0], &status, sizeof(status)); 61511d0f125SLuiz Capitulino if (ret == sizeof(status) && WIFEXITED(status) && 61611d0f125SLuiz Capitulino WEXITSTATUS(status) == SUSPEND_SUPPORTED) { 61711d0f125SLuiz Capitulino goto out; 61811d0f125SLuiz Capitulino } 61911d0f125SLuiz Capitulino 62011d0f125SLuiz Capitulino error_set(err, QERR_UNSUPPORTED); 62111d0f125SLuiz Capitulino 62211d0f125SLuiz Capitulino out: 62311d0f125SLuiz Capitulino close(pipefds[0]); 62411d0f125SLuiz Capitulino } 62511d0f125SLuiz Capitulino 62611d0f125SLuiz Capitulino static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, 62711d0f125SLuiz Capitulino Error **err) 62811d0f125SLuiz Capitulino { 62911d0f125SLuiz Capitulino pid_t pid; 63011d0f125SLuiz Capitulino char *pmutils_path; 63111d0f125SLuiz Capitulino 63211d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 63311d0f125SLuiz Capitulino 63411d0f125SLuiz Capitulino pid = fork(); 63511d0f125SLuiz Capitulino if (pid == 0) { 63611d0f125SLuiz Capitulino /* child */ 63711d0f125SLuiz Capitulino int fd; 63811d0f125SLuiz Capitulino 63911d0f125SLuiz Capitulino setsid(); 64011d0f125SLuiz Capitulino reopen_fd_to_null(0); 64111d0f125SLuiz Capitulino reopen_fd_to_null(1); 64211d0f125SLuiz Capitulino reopen_fd_to_null(2); 64311d0f125SLuiz Capitulino 64411d0f125SLuiz Capitulino if (pmutils_path) { 64511d0f125SLuiz Capitulino execle(pmutils_path, pmutils_bin, NULL, environ); 64611d0f125SLuiz Capitulino } 64711d0f125SLuiz Capitulino 64811d0f125SLuiz Capitulino /* 64911d0f125SLuiz Capitulino * If we get here either pm-utils is not installed or execle() has 65011d0f125SLuiz Capitulino * failed. Let's try the manual method if the caller wants it. 65111d0f125SLuiz Capitulino */ 65211d0f125SLuiz Capitulino 65311d0f125SLuiz Capitulino if (!sysfile_str) { 65411d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 65511d0f125SLuiz Capitulino } 65611d0f125SLuiz Capitulino 65711d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_WRONLY); 65811d0f125SLuiz Capitulino if (fd < 0) { 65911d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 66011d0f125SLuiz Capitulino } 66111d0f125SLuiz Capitulino 66211d0f125SLuiz Capitulino if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) { 66311d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 66411d0f125SLuiz Capitulino } 66511d0f125SLuiz Capitulino 66611d0f125SLuiz Capitulino _exit(EXIT_SUCCESS); 66711d0f125SLuiz Capitulino } 66811d0f125SLuiz Capitulino 66911d0f125SLuiz Capitulino g_free(pmutils_path); 67011d0f125SLuiz Capitulino 67111d0f125SLuiz Capitulino if (pid < 0) { 67211d0f125SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 67311d0f125SLuiz Capitulino return; 67411d0f125SLuiz Capitulino } 67511d0f125SLuiz Capitulino } 67611d0f125SLuiz Capitulino 67711d0f125SLuiz Capitulino void qmp_guest_suspend_disk(Error **err) 67811d0f125SLuiz Capitulino { 67911d0f125SLuiz Capitulino bios_supports_mode("pm-is-supported", "--hibernate", "disk", err); 68011d0f125SLuiz Capitulino if (error_is_set(err)) { 68111d0f125SLuiz Capitulino return; 68211d0f125SLuiz Capitulino } 68311d0f125SLuiz Capitulino 68411d0f125SLuiz Capitulino guest_suspend("pm-hibernate", "disk", err); 68511d0f125SLuiz Capitulino } 68611d0f125SLuiz Capitulino 687fbf42210SLuiz Capitulino void qmp_guest_suspend_ram(Error **err) 688fbf42210SLuiz Capitulino { 689fbf42210SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend", "mem", err); 690fbf42210SLuiz Capitulino if (error_is_set(err)) { 691fbf42210SLuiz Capitulino return; 692fbf42210SLuiz Capitulino } 693fbf42210SLuiz Capitulino 694fbf42210SLuiz Capitulino guest_suspend("pm-suspend", "mem", err); 695fbf42210SLuiz Capitulino } 696fbf42210SLuiz Capitulino 69795f4f404SLuiz Capitulino void qmp_guest_suspend_hybrid(Error **err) 69895f4f404SLuiz Capitulino { 69995f4f404SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err); 70095f4f404SLuiz Capitulino if (error_is_set(err)) { 70195f4f404SLuiz Capitulino return; 70295f4f404SLuiz Capitulino } 70395f4f404SLuiz Capitulino 70495f4f404SLuiz Capitulino guest_suspend("pm-suspend-hybrid", NULL, err); 70595f4f404SLuiz Capitulino } 70695f4f404SLuiz Capitulino 7073424fc9fSMichal Privoznik static GuestNetworkInterfaceList * 7083424fc9fSMichal Privoznik guest_find_interface(GuestNetworkInterfaceList *head, 7093424fc9fSMichal Privoznik const char *name) 7103424fc9fSMichal Privoznik { 7113424fc9fSMichal Privoznik for (; head; head = head->next) { 7123424fc9fSMichal Privoznik if (strcmp(head->value->name, name) == 0) { 7133424fc9fSMichal Privoznik break; 7143424fc9fSMichal Privoznik } 7153424fc9fSMichal Privoznik } 7163424fc9fSMichal Privoznik 7173424fc9fSMichal Privoznik return head; 7183424fc9fSMichal Privoznik } 7193424fc9fSMichal Privoznik 7203424fc9fSMichal Privoznik /* 7213424fc9fSMichal Privoznik * Build information about guest interfaces 7223424fc9fSMichal Privoznik */ 7233424fc9fSMichal Privoznik GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 7243424fc9fSMichal Privoznik { 7253424fc9fSMichal Privoznik GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; 7263424fc9fSMichal Privoznik struct ifaddrs *ifap, *ifa; 7273424fc9fSMichal Privoznik char err_msg[512]; 7283424fc9fSMichal Privoznik 7293424fc9fSMichal Privoznik if (getifaddrs(&ifap) < 0) { 7303424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 7313424fc9fSMichal Privoznik "getifaddrs failed: %s", strerror(errno)); 7323424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 7333424fc9fSMichal Privoznik goto error; 7343424fc9fSMichal Privoznik } 7353424fc9fSMichal Privoznik 7363424fc9fSMichal Privoznik for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 7373424fc9fSMichal Privoznik GuestNetworkInterfaceList *info; 7383424fc9fSMichal Privoznik GuestIpAddressList **address_list = NULL, *address_item = NULL; 7393424fc9fSMichal Privoznik char addr4[INET_ADDRSTRLEN]; 7403424fc9fSMichal Privoznik char addr6[INET6_ADDRSTRLEN]; 7413424fc9fSMichal Privoznik int sock; 7423424fc9fSMichal Privoznik struct ifreq ifr; 7433424fc9fSMichal Privoznik unsigned char *mac_addr; 7443424fc9fSMichal Privoznik void *p; 7453424fc9fSMichal Privoznik 7463424fc9fSMichal Privoznik g_debug("Processing %s interface", ifa->ifa_name); 7473424fc9fSMichal Privoznik 7483424fc9fSMichal Privoznik info = guest_find_interface(head, ifa->ifa_name); 7493424fc9fSMichal Privoznik 7503424fc9fSMichal Privoznik if (!info) { 7513424fc9fSMichal Privoznik info = g_malloc0(sizeof(*info)); 7523424fc9fSMichal Privoznik info->value = g_malloc0(sizeof(*info->value)); 7533424fc9fSMichal Privoznik info->value->name = g_strdup(ifa->ifa_name); 7543424fc9fSMichal Privoznik 7553424fc9fSMichal Privoznik if (!cur_item) { 7563424fc9fSMichal Privoznik head = cur_item = info; 7573424fc9fSMichal Privoznik } else { 7583424fc9fSMichal Privoznik cur_item->next = info; 7593424fc9fSMichal Privoznik cur_item = info; 7603424fc9fSMichal Privoznik } 7613424fc9fSMichal Privoznik } 7623424fc9fSMichal Privoznik 7633424fc9fSMichal Privoznik if (!info->value->has_hardware_address && 7643424fc9fSMichal Privoznik ifa->ifa_flags & SIOCGIFHWADDR) { 7653424fc9fSMichal Privoznik /* we haven't obtained HW address yet */ 7663424fc9fSMichal Privoznik sock = socket(PF_INET, SOCK_STREAM, 0); 7673424fc9fSMichal Privoznik if (sock == -1) { 7683424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 7693424fc9fSMichal Privoznik "failed to create socket: %s", strerror(errno)); 7703424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 7713424fc9fSMichal Privoznik goto error; 7723424fc9fSMichal Privoznik } 7733424fc9fSMichal Privoznik 7743424fc9fSMichal Privoznik memset(&ifr, 0, sizeof(ifr)); 7753424fc9fSMichal Privoznik strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE); 7763424fc9fSMichal Privoznik if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { 7773424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 7783424fc9fSMichal Privoznik "failed to get MAC addres of %s: %s", 7793424fc9fSMichal Privoznik ifa->ifa_name, 7803424fc9fSMichal Privoznik strerror(errno)); 7813424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 7823424fc9fSMichal Privoznik goto error; 7833424fc9fSMichal Privoznik } 7843424fc9fSMichal Privoznik 7853424fc9fSMichal Privoznik mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; 7863424fc9fSMichal Privoznik 7873424fc9fSMichal Privoznik if (asprintf(&info->value->hardware_address, 7883424fc9fSMichal Privoznik "%02x:%02x:%02x:%02x:%02x:%02x", 7893424fc9fSMichal Privoznik (int) mac_addr[0], (int) mac_addr[1], 7903424fc9fSMichal Privoznik (int) mac_addr[2], (int) mac_addr[3], 7913424fc9fSMichal Privoznik (int) mac_addr[4], (int) mac_addr[5]) == -1) { 7923424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 7933424fc9fSMichal Privoznik "failed to format MAC: %s", strerror(errno)); 7943424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 7953424fc9fSMichal Privoznik goto error; 7963424fc9fSMichal Privoznik } 7973424fc9fSMichal Privoznik 7983424fc9fSMichal Privoznik info->value->has_hardware_address = true; 7993424fc9fSMichal Privoznik close(sock); 8003424fc9fSMichal Privoznik } 8013424fc9fSMichal Privoznik 8023424fc9fSMichal Privoznik if (ifa->ifa_addr && 8033424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET) { 8043424fc9fSMichal Privoznik /* interface with IPv4 address */ 8053424fc9fSMichal Privoznik address_item = g_malloc0(sizeof(*address_item)); 8063424fc9fSMichal Privoznik address_item->value = g_malloc0(sizeof(*address_item->value)); 8073424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; 8083424fc9fSMichal Privoznik if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { 8093424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8103424fc9fSMichal Privoznik "inet_ntop failed : %s", strerror(errno)); 8113424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8123424fc9fSMichal Privoznik goto error; 8133424fc9fSMichal Privoznik } 8143424fc9fSMichal Privoznik 8153424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr4); 8163424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; 8173424fc9fSMichal Privoznik 8183424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 8193424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 8203424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 8213424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; 8223424fc9fSMichal Privoznik address_item->value->prefix = ctpop32(((uint32_t *) p)[0]); 8233424fc9fSMichal Privoznik } 8243424fc9fSMichal Privoznik } else if (ifa->ifa_addr && 8253424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET6) { 8263424fc9fSMichal Privoznik /* interface with IPv6 address */ 8273424fc9fSMichal Privoznik address_item = g_malloc0(sizeof(*address_item)); 8283424fc9fSMichal Privoznik address_item->value = g_malloc0(sizeof(*address_item->value)); 8293424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 8303424fc9fSMichal Privoznik if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { 8313424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8323424fc9fSMichal Privoznik "inet_ntop failed : %s", strerror(errno)); 8333424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8343424fc9fSMichal Privoznik goto error; 8353424fc9fSMichal Privoznik } 8363424fc9fSMichal Privoznik 8373424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr6); 8383424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; 8393424fc9fSMichal Privoznik 8403424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 8413424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 8423424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 8433424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 8443424fc9fSMichal Privoznik address_item->value->prefix = 8453424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[0]) + 8463424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[1]) + 8473424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[2]) + 8483424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[3]); 8493424fc9fSMichal Privoznik } 8503424fc9fSMichal Privoznik } 8513424fc9fSMichal Privoznik 8523424fc9fSMichal Privoznik if (!address_item) { 8533424fc9fSMichal Privoznik continue; 8543424fc9fSMichal Privoznik } 8553424fc9fSMichal Privoznik 8563424fc9fSMichal Privoznik address_list = &info->value->ip_addresses; 8573424fc9fSMichal Privoznik 8583424fc9fSMichal Privoznik while (*address_list && (*address_list)->next) { 8593424fc9fSMichal Privoznik address_list = &(*address_list)->next; 8603424fc9fSMichal Privoznik } 8613424fc9fSMichal Privoznik 8623424fc9fSMichal Privoznik if (!*address_list) { 8633424fc9fSMichal Privoznik *address_list = address_item; 8643424fc9fSMichal Privoznik } else { 8653424fc9fSMichal Privoznik (*address_list)->next = address_item; 8663424fc9fSMichal Privoznik } 8673424fc9fSMichal Privoznik 8683424fc9fSMichal Privoznik info->value->has_ip_addresses = true; 8693424fc9fSMichal Privoznik 8703424fc9fSMichal Privoznik 8713424fc9fSMichal Privoznik } 8723424fc9fSMichal Privoznik 8733424fc9fSMichal Privoznik freeifaddrs(ifap); 8743424fc9fSMichal Privoznik return head; 8753424fc9fSMichal Privoznik 8763424fc9fSMichal Privoznik error: 8773424fc9fSMichal Privoznik freeifaddrs(ifap); 8783424fc9fSMichal Privoznik qapi_free_GuestNetworkInterfaceList(head); 8793424fc9fSMichal Privoznik return NULL; 8803424fc9fSMichal Privoznik } 8813424fc9fSMichal Privoznik 882e72c3f2eSMichael Roth #else /* defined(__linux__) */ 883e72c3f2eSMichael Roth 884e72c3f2eSMichael Roth void qmp_guest_suspend_disk(Error **err) 885e72c3f2eSMichael Roth { 886e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 887e72c3f2eSMichael Roth } 888e72c3f2eSMichael Roth 889e72c3f2eSMichael Roth void qmp_guest_suspend_ram(Error **err) 890e72c3f2eSMichael Roth { 891e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 892e72c3f2eSMichael Roth } 893e72c3f2eSMichael Roth 894e72c3f2eSMichael Roth void qmp_guest_suspend_hybrid(Error **err) 895e72c3f2eSMichael Roth { 896e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 897e72c3f2eSMichael Roth } 898e72c3f2eSMichael Roth 899e72c3f2eSMichael Roth GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 900e72c3f2eSMichael Roth { 901e72c3f2eSMichael Roth error_set(errp, QERR_UNSUPPORTED); 902e72c3f2eSMichael Roth return NULL; 903e72c3f2eSMichael Roth } 904e72c3f2eSMichael Roth 905e72c3f2eSMichael Roth #endif 906e72c3f2eSMichael Roth 907*d35d4cb5SMichael Roth #if !defined(CONFIG_FSFREEZE) 908*d35d4cb5SMichael Roth 909*d35d4cb5SMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 910*d35d4cb5SMichael Roth { 911*d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 912*d35d4cb5SMichael Roth 913*d35d4cb5SMichael Roth return 0; 914*d35d4cb5SMichael Roth } 915*d35d4cb5SMichael Roth 916*d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 917*d35d4cb5SMichael Roth { 918*d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 919*d35d4cb5SMichael Roth 920*d35d4cb5SMichael Roth return 0; 921*d35d4cb5SMichael Roth } 922*d35d4cb5SMichael Roth 923*d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 924*d35d4cb5SMichael Roth { 925*d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 926*d35d4cb5SMichael Roth 927*d35d4cb5SMichael Roth return 0; 928*d35d4cb5SMichael Roth } 929*d35d4cb5SMichael Roth 930*d35d4cb5SMichael Roth #endif 931*d35d4cb5SMichael Roth 932c216e5adSMichael Roth /* register init/cleanup routines for stateful command groups */ 933c216e5adSMichael Roth void ga_command_state_init(GAState *s, GACommandState *cs) 934c216e5adSMichael Roth { 935c216e5adSMichael Roth #if defined(CONFIG_FSFREEZE) 936c216e5adSMichael Roth ga_command_state_add(cs, guest_fsfreeze_init, guest_fsfreeze_cleanup); 937c216e5adSMichael Roth #endif 938c216e5adSMichael Roth ga_command_state_add(cs, guest_file_init, NULL); 939c216e5adSMichael Roth } 940