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