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> 172c02cbf6SLuiz Capitulino #include <sys/wait.h> 18c216e5adSMichael Roth #include "qga/guest-agent-core.h" 19c216e5adSMichael Roth #include "qga-qmp-commands.h" 207b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 21*1de7afc9SPaolo Bonzini #include "qemu/queue.h" 22*1de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 23c216e5adSMichael Roth 242c02cbf6SLuiz Capitulino #ifndef CONFIG_HAS_ENVIRON 25eecae147SAndreas Färber #ifdef __APPLE__ 26eecae147SAndreas Färber #include <crt_externs.h> 27eecae147SAndreas Färber #define environ (*_NSGetEnviron()) 28eecae147SAndreas Färber #else 292c02cbf6SLuiz Capitulino extern char **environ; 302c02cbf6SLuiz Capitulino #endif 31eecae147SAndreas Färber #endif 322c02cbf6SLuiz Capitulino 33e72c3f2eSMichael Roth #if defined(__linux__) 34e72c3f2eSMichael Roth #include <mntent.h> 35e72c3f2eSMichael Roth #include <linux/fs.h> 36e72c3f2eSMichael Roth #include <ifaddrs.h> 37e72c3f2eSMichael Roth #include <arpa/inet.h> 38e72c3f2eSMichael Roth #include <sys/socket.h> 39e72c3f2eSMichael Roth #include <net/if.h> 40e72c3f2eSMichael Roth 41eab5fd59SPaolo Bonzini #ifdef FIFREEZE 42e72c3f2eSMichael Roth #define CONFIG_FSFREEZE 43e72c3f2eSMichael Roth #endif 44eab5fd59SPaolo Bonzini #ifdef FITRIM 45eab5fd59SPaolo Bonzini #define CONFIG_FSTRIM 46eab5fd59SPaolo Bonzini #endif 47e72c3f2eSMichael Roth #endif 48e72c3f2eSMichael Roth 49c216e5adSMichael Roth void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) 50c216e5adSMichael Roth { 51c216e5adSMichael Roth const char *shutdown_flag; 52d5dd3498SLuiz Capitulino pid_t rpid, pid; 533674838cSLuiz Capitulino int status; 54c216e5adSMichael Roth 55c216e5adSMichael Roth slog("guest-shutdown called, mode: %s", mode); 56c216e5adSMichael Roth if (!has_mode || strcmp(mode, "powerdown") == 0) { 57c216e5adSMichael Roth shutdown_flag = "-P"; 58c216e5adSMichael Roth } else if (strcmp(mode, "halt") == 0) { 59c216e5adSMichael Roth shutdown_flag = "-H"; 60c216e5adSMichael Roth } else if (strcmp(mode, "reboot") == 0) { 61c216e5adSMichael Roth shutdown_flag = "-r"; 62c216e5adSMichael Roth } else { 63c216e5adSMichael Roth error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode", 64c216e5adSMichael Roth "halt|powerdown|reboot"); 65c216e5adSMichael Roth return; 66c216e5adSMichael Roth } 67c216e5adSMichael Roth 68d5dd3498SLuiz Capitulino pid = fork(); 69d5dd3498SLuiz Capitulino if (pid == 0) { 70c216e5adSMichael Roth /* child, start the shutdown */ 71c216e5adSMichael Roth setsid(); 723674838cSLuiz Capitulino reopen_fd_to_null(0); 733674838cSLuiz Capitulino reopen_fd_to_null(1); 743674838cSLuiz Capitulino reopen_fd_to_null(2); 75c216e5adSMichael Roth 763674838cSLuiz Capitulino execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0", 773674838cSLuiz Capitulino "hypervisor initiated shutdown", (char*)NULL, environ); 783674838cSLuiz Capitulino _exit(EXIT_FAILURE); 79d5dd3498SLuiz Capitulino } else if (pid < 0) { 80d5dd3498SLuiz Capitulino goto exit_err; 81c216e5adSMichael Roth } 82d5dd3498SLuiz Capitulino 83d5dd3498SLuiz Capitulino do { 84d5dd3498SLuiz Capitulino rpid = waitpid(pid, &status, 0); 85d5dd3498SLuiz Capitulino } while (rpid == -1 && errno == EINTR); 86d5dd3498SLuiz Capitulino if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { 87d5dd3498SLuiz Capitulino return; 88d5dd3498SLuiz Capitulino } 89d5dd3498SLuiz Capitulino 90d5dd3498SLuiz Capitulino exit_err: 91d5dd3498SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 92c216e5adSMichael Roth } 93c216e5adSMichael Roth 94c216e5adSMichael Roth typedef struct GuestFileHandle { 95c216e5adSMichael Roth uint64_t id; 96c216e5adSMichael Roth FILE *fh; 97c216e5adSMichael Roth QTAILQ_ENTRY(GuestFileHandle) next; 98c216e5adSMichael Roth } GuestFileHandle; 99c216e5adSMichael Roth 100c216e5adSMichael Roth static struct { 101c216e5adSMichael Roth QTAILQ_HEAD(, GuestFileHandle) filehandles; 102c216e5adSMichael Roth } guest_file_state; 103c216e5adSMichael Roth 104c216e5adSMichael Roth static void guest_file_handle_add(FILE *fh) 105c216e5adSMichael Roth { 106c216e5adSMichael Roth GuestFileHandle *gfh; 107c216e5adSMichael Roth 108c216e5adSMichael Roth gfh = g_malloc0(sizeof(GuestFileHandle)); 109c216e5adSMichael Roth gfh->id = fileno(fh); 110c216e5adSMichael Roth gfh->fh = fh; 111c216e5adSMichael Roth QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); 112c216e5adSMichael Roth } 113c216e5adSMichael Roth 114c216e5adSMichael Roth static GuestFileHandle *guest_file_handle_find(int64_t id) 115c216e5adSMichael Roth { 116c216e5adSMichael Roth GuestFileHandle *gfh; 117c216e5adSMichael Roth 118c216e5adSMichael Roth QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) 119c216e5adSMichael Roth { 120c216e5adSMichael Roth if (gfh->id == id) { 121c216e5adSMichael Roth return gfh; 122c216e5adSMichael Roth } 123c216e5adSMichael Roth } 124c216e5adSMichael Roth 125c216e5adSMichael Roth return NULL; 126c216e5adSMichael Roth } 127c216e5adSMichael Roth 128c216e5adSMichael Roth int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err) 129c216e5adSMichael Roth { 130c216e5adSMichael Roth FILE *fh; 131c216e5adSMichael Roth int fd; 132c216e5adSMichael Roth int64_t ret = -1; 133c216e5adSMichael Roth 134c216e5adSMichael Roth if (!has_mode) { 135c216e5adSMichael Roth mode = "r"; 136c216e5adSMichael Roth } 137c216e5adSMichael Roth slog("guest-file-open called, filepath: %s, mode: %s", path, mode); 138c216e5adSMichael Roth fh = fopen(path, mode); 139c216e5adSMichael Roth if (!fh) { 140c216e5adSMichael Roth error_set(err, QERR_OPEN_FILE_FAILED, path); 141c216e5adSMichael Roth return -1; 142c216e5adSMichael Roth } 143c216e5adSMichael Roth 144c216e5adSMichael Roth /* set fd non-blocking to avoid common use cases (like reading from a 145c216e5adSMichael Roth * named pipe) from hanging the agent 146c216e5adSMichael Roth */ 147c216e5adSMichael Roth fd = fileno(fh); 148c216e5adSMichael Roth ret = fcntl(fd, F_GETFL); 149c216e5adSMichael Roth ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK); 150c216e5adSMichael Roth if (ret == -1) { 151c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed"); 152c216e5adSMichael Roth fclose(fh); 153c216e5adSMichael Roth return -1; 154c216e5adSMichael Roth } 155c216e5adSMichael Roth 156c216e5adSMichael Roth guest_file_handle_add(fh); 157c216e5adSMichael Roth slog("guest-file-open, handle: %d", fd); 158c216e5adSMichael Roth return fd; 159c216e5adSMichael Roth } 160c216e5adSMichael Roth 161c216e5adSMichael Roth void qmp_guest_file_close(int64_t handle, Error **err) 162c216e5adSMichael Roth { 163c216e5adSMichael Roth GuestFileHandle *gfh = guest_file_handle_find(handle); 164c216e5adSMichael Roth int ret; 165c216e5adSMichael Roth 166c216e5adSMichael Roth slog("guest-file-close called, handle: %ld", handle); 167c216e5adSMichael Roth if (!gfh) { 168c216e5adSMichael Roth error_set(err, QERR_FD_NOT_FOUND, "handle"); 169c216e5adSMichael Roth return; 170c216e5adSMichael Roth } 171c216e5adSMichael Roth 172c216e5adSMichael Roth ret = fclose(gfh->fh); 173c216e5adSMichael Roth if (ret == -1) { 174c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed"); 175c216e5adSMichael Roth return; 176c216e5adSMichael Roth } 177c216e5adSMichael Roth 178c216e5adSMichael Roth QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next); 179c216e5adSMichael Roth g_free(gfh); 180c216e5adSMichael Roth } 181c216e5adSMichael Roth 182c216e5adSMichael Roth struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, 183c216e5adSMichael Roth int64_t count, Error **err) 184c216e5adSMichael Roth { 185c216e5adSMichael Roth GuestFileHandle *gfh = guest_file_handle_find(handle); 186c216e5adSMichael Roth GuestFileRead *read_data = NULL; 187c216e5adSMichael Roth guchar *buf; 188c216e5adSMichael Roth FILE *fh; 189c216e5adSMichael Roth size_t read_count; 190c216e5adSMichael Roth 191c216e5adSMichael Roth if (!gfh) { 192c216e5adSMichael Roth error_set(err, QERR_FD_NOT_FOUND, "handle"); 193c216e5adSMichael Roth return NULL; 194c216e5adSMichael Roth } 195c216e5adSMichael Roth 196c216e5adSMichael Roth if (!has_count) { 197c216e5adSMichael Roth count = QGA_READ_COUNT_DEFAULT; 198c216e5adSMichael Roth } else if (count < 0) { 199c216e5adSMichael Roth error_set(err, QERR_INVALID_PARAMETER, "count"); 200c216e5adSMichael Roth return NULL; 201c216e5adSMichael Roth } 202c216e5adSMichael Roth 203c216e5adSMichael Roth fh = gfh->fh; 204c216e5adSMichael Roth buf = g_malloc0(count+1); 205c216e5adSMichael Roth read_count = fread(buf, 1, count, fh); 206c216e5adSMichael Roth if (ferror(fh)) { 207c216e5adSMichael Roth slog("guest-file-read failed, handle: %ld", handle); 208c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed"); 209c216e5adSMichael Roth } else { 210c216e5adSMichael Roth buf[read_count] = 0; 211c216e5adSMichael Roth read_data = g_malloc0(sizeof(GuestFileRead)); 212c216e5adSMichael Roth read_data->count = read_count; 213c216e5adSMichael Roth read_data->eof = feof(fh); 214c216e5adSMichael Roth if (read_count) { 215c216e5adSMichael Roth read_data->buf_b64 = g_base64_encode(buf, read_count); 216c216e5adSMichael Roth } 217c216e5adSMichael Roth } 218c216e5adSMichael Roth g_free(buf); 219c216e5adSMichael Roth clearerr(fh); 220c216e5adSMichael Roth 221c216e5adSMichael Roth return read_data; 222c216e5adSMichael Roth } 223c216e5adSMichael Roth 224c216e5adSMichael Roth GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, 225c216e5adSMichael Roth bool has_count, int64_t count, Error **err) 226c216e5adSMichael Roth { 227c216e5adSMichael Roth GuestFileWrite *write_data = NULL; 228c216e5adSMichael Roth guchar *buf; 229c216e5adSMichael Roth gsize buf_len; 230c216e5adSMichael Roth int write_count; 231c216e5adSMichael Roth GuestFileHandle *gfh = guest_file_handle_find(handle); 232c216e5adSMichael Roth FILE *fh; 233c216e5adSMichael Roth 234c216e5adSMichael Roth if (!gfh) { 235c216e5adSMichael Roth error_set(err, QERR_FD_NOT_FOUND, "handle"); 236c216e5adSMichael Roth return NULL; 237c216e5adSMichael Roth } 238c216e5adSMichael Roth 239c216e5adSMichael Roth fh = gfh->fh; 240c216e5adSMichael Roth buf = g_base64_decode(buf_b64, &buf_len); 241c216e5adSMichael Roth 242c216e5adSMichael Roth if (!has_count) { 243c216e5adSMichael Roth count = buf_len; 244c216e5adSMichael Roth } else if (count < 0 || count > buf_len) { 245c216e5adSMichael Roth g_free(buf); 246c216e5adSMichael Roth error_set(err, QERR_INVALID_PARAMETER, "count"); 247c216e5adSMichael Roth return NULL; 248c216e5adSMichael Roth } 249c216e5adSMichael Roth 250c216e5adSMichael Roth write_count = fwrite(buf, 1, count, fh); 251c216e5adSMichael Roth if (ferror(fh)) { 252c216e5adSMichael Roth slog("guest-file-write failed, handle: %ld", handle); 253c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error"); 254c216e5adSMichael Roth } else { 255c216e5adSMichael Roth write_data = g_malloc0(sizeof(GuestFileWrite)); 256c216e5adSMichael Roth write_data->count = write_count; 257c216e5adSMichael Roth write_data->eof = feof(fh); 258c216e5adSMichael Roth } 259c216e5adSMichael Roth g_free(buf); 260c216e5adSMichael Roth clearerr(fh); 261c216e5adSMichael Roth 262c216e5adSMichael Roth return write_data; 263c216e5adSMichael Roth } 264c216e5adSMichael Roth 265c216e5adSMichael Roth struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, 266c216e5adSMichael Roth int64_t whence, Error **err) 267c216e5adSMichael Roth { 268c216e5adSMichael Roth GuestFileHandle *gfh = guest_file_handle_find(handle); 269c216e5adSMichael Roth GuestFileSeek *seek_data = NULL; 270c216e5adSMichael Roth FILE *fh; 271c216e5adSMichael Roth int ret; 272c216e5adSMichael Roth 273c216e5adSMichael Roth if (!gfh) { 274c216e5adSMichael Roth error_set(err, QERR_FD_NOT_FOUND, "handle"); 275c216e5adSMichael Roth return NULL; 276c216e5adSMichael Roth } 277c216e5adSMichael Roth 278c216e5adSMichael Roth fh = gfh->fh; 279c216e5adSMichael Roth ret = fseek(fh, offset, whence); 280c216e5adSMichael Roth if (ret == -1) { 281c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); 282c216e5adSMichael Roth } else { 283c216e5adSMichael Roth seek_data = g_malloc0(sizeof(GuestFileRead)); 284c216e5adSMichael Roth seek_data->position = ftell(fh); 285c216e5adSMichael Roth seek_data->eof = feof(fh); 286c216e5adSMichael Roth } 287c216e5adSMichael Roth clearerr(fh); 288c216e5adSMichael Roth 289c216e5adSMichael Roth return seek_data; 290c216e5adSMichael Roth } 291c216e5adSMichael Roth 292c216e5adSMichael Roth void qmp_guest_file_flush(int64_t handle, Error **err) 293c216e5adSMichael Roth { 294c216e5adSMichael Roth GuestFileHandle *gfh = guest_file_handle_find(handle); 295c216e5adSMichael Roth FILE *fh; 296c216e5adSMichael Roth int ret; 297c216e5adSMichael Roth 298c216e5adSMichael Roth if (!gfh) { 299c216e5adSMichael Roth error_set(err, QERR_FD_NOT_FOUND, "handle"); 300c216e5adSMichael Roth return; 301c216e5adSMichael Roth } 302c216e5adSMichael Roth 303c216e5adSMichael Roth fh = gfh->fh; 304c216e5adSMichael Roth ret = fflush(fh); 305c216e5adSMichael Roth if (ret == EOF) { 306c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); 307c216e5adSMichael Roth } 308c216e5adSMichael Roth } 309c216e5adSMichael Roth 310c216e5adSMichael Roth static void guest_file_init(void) 311c216e5adSMichael Roth { 312c216e5adSMichael Roth QTAILQ_INIT(&guest_file_state.filehandles); 313c216e5adSMichael Roth } 314c216e5adSMichael Roth 315e72c3f2eSMichael Roth /* linux-specific implementations. avoid this if at all possible. */ 316e72c3f2eSMichael Roth #if defined(__linux__) 317e72c3f2eSMichael Roth 318eab5fd59SPaolo Bonzini #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) 319af02203fSPaolo Bonzini typedef struct FsMount { 320c216e5adSMichael Roth char *dirname; 321c216e5adSMichael Roth char *devtype; 322af02203fSPaolo Bonzini QTAILQ_ENTRY(FsMount) next; 323af02203fSPaolo Bonzini } FsMount; 324c216e5adSMichael Roth 325af02203fSPaolo Bonzini typedef QTAILQ_HEAD(, FsMount) FsMountList; 3269e8aded4SMichael Roth 327af02203fSPaolo Bonzini static void free_fs_mount_list(FsMountList *mounts) 328c216e5adSMichael Roth { 329af02203fSPaolo Bonzini FsMount *mount, *temp; 330c216e5adSMichael Roth 3319e8aded4SMichael Roth if (!mounts) { 3329e8aded4SMichael Roth return; 3339e8aded4SMichael Roth } 3349e8aded4SMichael Roth 3359e8aded4SMichael Roth QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) { 3369e8aded4SMichael Roth QTAILQ_REMOVE(mounts, mount, next); 337c216e5adSMichael Roth g_free(mount->dirname); 338c216e5adSMichael Roth g_free(mount->devtype); 339c216e5adSMichael Roth g_free(mount); 340c216e5adSMichael Roth } 3419e8aded4SMichael Roth } 3429e8aded4SMichael Roth 3439e8aded4SMichael Roth /* 3449e8aded4SMichael Roth * Walk the mount table and build a list of local file systems 3459e8aded4SMichael Roth */ 346af02203fSPaolo Bonzini static int build_fs_mount_list(FsMountList *mounts) 3479e8aded4SMichael Roth { 3489e8aded4SMichael Roth struct mntent *ment; 349af02203fSPaolo Bonzini FsMount *mount; 3509e2fa418SMichael Roth char const *mtab = "/proc/self/mounts"; 3519e8aded4SMichael Roth FILE *fp; 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 372af02203fSPaolo Bonzini mount = g_malloc0(sizeof(FsMount)); 373c216e5adSMichael Roth mount->dirname = g_strdup(ment->mnt_dir); 374c216e5adSMichael Roth mount->devtype = g_strdup(ment->mnt_type); 375c216e5adSMichael Roth 3769e8aded4SMichael Roth QTAILQ_INSERT_TAIL(mounts, mount, next); 377c216e5adSMichael Roth } 378c216e5adSMichael Roth 379c216e5adSMichael Roth endmntent(fp); 380c216e5adSMichael Roth 381c216e5adSMichael Roth return 0; 382c216e5adSMichael Roth } 383eab5fd59SPaolo Bonzini #endif 384eab5fd59SPaolo Bonzini 385eab5fd59SPaolo Bonzini #if defined(CONFIG_FSFREEZE) 386c216e5adSMichael Roth 387c216e5adSMichael Roth /* 388c216e5adSMichael Roth * Return status of freeze/thaw 389c216e5adSMichael Roth */ 390c216e5adSMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 391c216e5adSMichael Roth { 392f22d85e9SMichael Roth if (ga_is_frozen(ga_state)) { 393f22d85e9SMichael Roth return GUEST_FSFREEZE_STATUS_FROZEN; 394f22d85e9SMichael Roth } 395f22d85e9SMichael Roth 396f22d85e9SMichael Roth return GUEST_FSFREEZE_STATUS_THAWED; 397c216e5adSMichael Roth } 398c216e5adSMichael Roth 399c216e5adSMichael Roth /* 400c216e5adSMichael Roth * Walk list of mounted file systems in the guest, and freeze the ones which 401c216e5adSMichael Roth * are real local file systems. 402c216e5adSMichael Roth */ 403c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 404c216e5adSMichael Roth { 405c216e5adSMichael Roth int ret = 0, i = 0; 406af02203fSPaolo Bonzini FsMountList mounts; 407af02203fSPaolo Bonzini struct FsMount *mount; 408c216e5adSMichael Roth int fd; 409c216e5adSMichael Roth char err_msg[512]; 410c216e5adSMichael Roth 411c216e5adSMichael Roth slog("guest-fsfreeze called"); 412c216e5adSMichael Roth 4139e8aded4SMichael Roth QTAILQ_INIT(&mounts); 414af02203fSPaolo Bonzini ret = build_fs_mount_list(&mounts); 415c216e5adSMichael Roth if (ret < 0) { 416c216e5adSMichael Roth return ret; 417c216e5adSMichael Roth } 418c216e5adSMichael Roth 419c216e5adSMichael Roth /* cannot risk guest agent blocking itself on a write in this state */ 420f22d85e9SMichael Roth ga_set_frozen(ga_state); 421c216e5adSMichael Roth 4229e8aded4SMichael Roth QTAILQ_FOREACH(mount, &mounts, next) { 423c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 424c216e5adSMichael Roth if (fd == -1) { 4259e8aded4SMichael Roth sprintf(err_msg, "failed to open %s, %s", mount->dirname, 4269e8aded4SMichael Roth strerror(errno)); 427c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 428c216e5adSMichael Roth goto error; 429c216e5adSMichael Roth } 430c216e5adSMichael Roth 431c216e5adSMichael Roth /* we try to cull filesytems we know won't work in advance, but other 432c216e5adSMichael Roth * filesytems may not implement fsfreeze for less obvious reasons. 4339e8aded4SMichael Roth * these will report EOPNOTSUPP. we simply ignore these when tallying 4349e8aded4SMichael Roth * the number of frozen filesystems. 4359e8aded4SMichael Roth * 4369e8aded4SMichael Roth * any other error means a failure to freeze a filesystem we 4379e8aded4SMichael Roth * expect to be freezable, so return an error in those cases 4389e8aded4SMichael Roth * and return system to thawed state. 439c216e5adSMichael Roth */ 440c216e5adSMichael Roth ret = ioctl(fd, FIFREEZE); 4419e8aded4SMichael Roth if (ret == -1) { 4429e8aded4SMichael Roth if (errno != EOPNOTSUPP) { 4439e8aded4SMichael Roth sprintf(err_msg, "failed to freeze %s, %s", 4449e8aded4SMichael Roth mount->dirname, strerror(errno)); 445c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 446c216e5adSMichael Roth close(fd); 447c216e5adSMichael Roth goto error; 448c216e5adSMichael Roth } 4499e8aded4SMichael Roth } else { 450c216e5adSMichael Roth i++; 451c216e5adSMichael Roth } 4529e8aded4SMichael Roth close(fd); 4539e8aded4SMichael Roth } 454c216e5adSMichael Roth 455af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 456c216e5adSMichael Roth return i; 457c216e5adSMichael Roth 458c216e5adSMichael Roth error: 459af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 460c216e5adSMichael Roth qmp_guest_fsfreeze_thaw(NULL); 461c216e5adSMichael Roth return 0; 462c216e5adSMichael Roth } 463c216e5adSMichael Roth 464c216e5adSMichael Roth /* 465c216e5adSMichael Roth * Walk list of frozen file systems in the guest, and thaw them. 466c216e5adSMichael Roth */ 467c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 468c216e5adSMichael Roth { 469c216e5adSMichael Roth int ret; 470af02203fSPaolo Bonzini FsMountList mounts; 471af02203fSPaolo Bonzini FsMount *mount; 4729e8aded4SMichael Roth int fd, i = 0, logged; 473c216e5adSMichael Roth 4749e8aded4SMichael Roth QTAILQ_INIT(&mounts); 475af02203fSPaolo Bonzini ret = build_fs_mount_list(&mounts); 4769e8aded4SMichael Roth if (ret) { 4779e8aded4SMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, 4789e8aded4SMichael Roth "failed to enumerate filesystems"); 4799e8aded4SMichael Roth return 0; 4809e8aded4SMichael Roth } 4819e8aded4SMichael Roth 4829e8aded4SMichael Roth QTAILQ_FOREACH(mount, &mounts, next) { 4839e8aded4SMichael Roth logged = false; 484c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 485c216e5adSMichael Roth if (fd == -1) { 486c216e5adSMichael Roth continue; 487c216e5adSMichael Roth } 4889e8aded4SMichael Roth /* we have no way of knowing whether a filesystem was actually unfrozen 4899e8aded4SMichael Roth * as a result of a successful call to FITHAW, only that if an error 4909e8aded4SMichael Roth * was returned the filesystem was *not* unfrozen by that particular 4919e8aded4SMichael Roth * call. 4929e8aded4SMichael Roth * 493a31f0531SJim Meyering * since multiple preceding FIFREEZEs require multiple calls to FITHAW 4949e8aded4SMichael Roth * to unfreeze, continuing issuing FITHAW until an error is returned, 4959e8aded4SMichael Roth * in which case either the filesystem is in an unfreezable state, or, 4969e8aded4SMichael Roth * more likely, it was thawed previously (and remains so afterward). 4979e8aded4SMichael Roth * 4989e8aded4SMichael Roth * also, since the most recent successful call is the one that did 4999e8aded4SMichael Roth * the actual unfreeze, we can use this to provide an accurate count 5009e8aded4SMichael Roth * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which 5019e8aded4SMichael Roth * may * be useful for determining whether a filesystem was unfrozen 5029e8aded4SMichael Roth * during the freeze/thaw phase by a process other than qemu-ga. 5039e8aded4SMichael Roth */ 5049e8aded4SMichael Roth do { 505c216e5adSMichael Roth ret = ioctl(fd, FITHAW); 5069e8aded4SMichael Roth if (ret == 0 && !logged) { 507c216e5adSMichael Roth i++; 5089e8aded4SMichael Roth logged = true; 5099e8aded4SMichael Roth } 5109e8aded4SMichael Roth } while (ret == 0); 5119e8aded4SMichael Roth close(fd); 512c216e5adSMichael Roth } 513c216e5adSMichael Roth 514f22d85e9SMichael Roth ga_unset_frozen(ga_state); 515af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 516c216e5adSMichael Roth return i; 517c216e5adSMichael Roth } 518c216e5adSMichael Roth 519c216e5adSMichael Roth static void guest_fsfreeze_cleanup(void) 520c216e5adSMichael Roth { 521c216e5adSMichael Roth int64_t ret; 522c216e5adSMichael Roth Error *err = NULL; 523c216e5adSMichael Roth 524f22d85e9SMichael Roth if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { 525c216e5adSMichael Roth ret = qmp_guest_fsfreeze_thaw(&err); 526c216e5adSMichael Roth if (ret < 0 || err) { 527c216e5adSMichael Roth slog("failed to clean up frozen filesystems"); 528c216e5adSMichael Roth } 529c216e5adSMichael Roth } 530c216e5adSMichael Roth } 531e72c3f2eSMichael Roth #endif /* CONFIG_FSFREEZE */ 532c216e5adSMichael Roth 533eab5fd59SPaolo Bonzini #if defined(CONFIG_FSTRIM) 534eab5fd59SPaolo Bonzini /* 535eab5fd59SPaolo Bonzini * Walk list of mounted file systems in the guest, and trim them. 536eab5fd59SPaolo Bonzini */ 537eab5fd59SPaolo Bonzini void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) 538eab5fd59SPaolo Bonzini { 539eab5fd59SPaolo Bonzini int ret = 0; 540eab5fd59SPaolo Bonzini FsMountList mounts; 541eab5fd59SPaolo Bonzini struct FsMount *mount; 542eab5fd59SPaolo Bonzini int fd; 543eab5fd59SPaolo Bonzini char err_msg[512]; 544eab5fd59SPaolo Bonzini struct fstrim_range r = { 545eab5fd59SPaolo Bonzini .start = 0, 546eab5fd59SPaolo Bonzini .len = -1, 547eab5fd59SPaolo Bonzini .minlen = has_minimum ? minimum : 0, 548eab5fd59SPaolo Bonzini }; 549eab5fd59SPaolo Bonzini 550eab5fd59SPaolo Bonzini slog("guest-fstrim called"); 551eab5fd59SPaolo Bonzini 552eab5fd59SPaolo Bonzini QTAILQ_INIT(&mounts); 553eab5fd59SPaolo Bonzini ret = build_fs_mount_list(&mounts); 554eab5fd59SPaolo Bonzini if (ret < 0) { 555eab5fd59SPaolo Bonzini return; 556eab5fd59SPaolo Bonzini } 557eab5fd59SPaolo Bonzini 558eab5fd59SPaolo Bonzini QTAILQ_FOREACH(mount, &mounts, next) { 559eab5fd59SPaolo Bonzini fd = qemu_open(mount->dirname, O_RDONLY); 560eab5fd59SPaolo Bonzini if (fd == -1) { 561eab5fd59SPaolo Bonzini sprintf(err_msg, "failed to open %s, %s", mount->dirname, 562eab5fd59SPaolo Bonzini strerror(errno)); 563eab5fd59SPaolo Bonzini error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 564eab5fd59SPaolo Bonzini goto error; 565eab5fd59SPaolo Bonzini } 566eab5fd59SPaolo Bonzini 567eab5fd59SPaolo Bonzini /* We try to cull filesytems we know won't work in advance, but other 568eab5fd59SPaolo Bonzini * filesytems may not implement fstrim for less obvious reasons. These 569eab5fd59SPaolo Bonzini * will report EOPNOTSUPP; we simply ignore these errors. Any other 570eab5fd59SPaolo Bonzini * error means an unexpected error, so return it in those cases. In 571eab5fd59SPaolo Bonzini * some other cases ENOTTY will be reported (e.g. CD-ROMs). 572eab5fd59SPaolo Bonzini */ 573eab5fd59SPaolo Bonzini ret = ioctl(fd, FITRIM, &r); 574eab5fd59SPaolo Bonzini if (ret == -1) { 575eab5fd59SPaolo Bonzini if (errno != ENOTTY && errno != EOPNOTSUPP) { 576eab5fd59SPaolo Bonzini sprintf(err_msg, "failed to trim %s, %s", 577eab5fd59SPaolo Bonzini mount->dirname, strerror(errno)); 578eab5fd59SPaolo Bonzini error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 579eab5fd59SPaolo Bonzini close(fd); 580eab5fd59SPaolo Bonzini goto error; 581eab5fd59SPaolo Bonzini } 582eab5fd59SPaolo Bonzini } 583eab5fd59SPaolo Bonzini close(fd); 584eab5fd59SPaolo Bonzini } 585eab5fd59SPaolo Bonzini 586eab5fd59SPaolo Bonzini error: 587eab5fd59SPaolo Bonzini free_fs_mount_list(&mounts); 588eab5fd59SPaolo Bonzini } 589eab5fd59SPaolo Bonzini #endif /* CONFIG_FSTRIM */ 590eab5fd59SPaolo Bonzini 591eab5fd59SPaolo Bonzini 59211d0f125SLuiz Capitulino #define LINUX_SYS_STATE_FILE "/sys/power/state" 59311d0f125SLuiz Capitulino #define SUSPEND_SUPPORTED 0 59411d0f125SLuiz Capitulino #define SUSPEND_NOT_SUPPORTED 1 59511d0f125SLuiz Capitulino 59611d0f125SLuiz Capitulino static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, 59711d0f125SLuiz Capitulino const char *sysfile_str, Error **err) 59811d0f125SLuiz Capitulino { 59911d0f125SLuiz Capitulino char *pmutils_path; 600dc8764f0SLuiz Capitulino pid_t pid, rpid; 601dc8764f0SLuiz Capitulino int status; 60211d0f125SLuiz Capitulino 60311d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 60411d0f125SLuiz Capitulino 60511d0f125SLuiz Capitulino pid = fork(); 60611d0f125SLuiz Capitulino if (!pid) { 607dc8764f0SLuiz Capitulino char buf[32]; /* hopefully big enough */ 608dc8764f0SLuiz Capitulino ssize_t ret; 609dc8764f0SLuiz Capitulino int fd; 61011d0f125SLuiz Capitulino 61111d0f125SLuiz Capitulino setsid(); 61211d0f125SLuiz Capitulino reopen_fd_to_null(0); 61311d0f125SLuiz Capitulino reopen_fd_to_null(1); 61411d0f125SLuiz Capitulino reopen_fd_to_null(2); 61511d0f125SLuiz Capitulino 61611d0f125SLuiz Capitulino if (pmutils_path) { 61711d0f125SLuiz Capitulino execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ); 61811d0f125SLuiz Capitulino } 61911d0f125SLuiz Capitulino 62011d0f125SLuiz Capitulino /* 62111d0f125SLuiz Capitulino * If we get here either pm-utils is not installed or execle() has 62211d0f125SLuiz Capitulino * failed. Let's try the manual method if the caller wants it. 62311d0f125SLuiz Capitulino */ 62411d0f125SLuiz Capitulino 62511d0f125SLuiz Capitulino if (!sysfile_str) { 62611d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 62711d0f125SLuiz Capitulino } 62811d0f125SLuiz Capitulino 62911d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); 63011d0f125SLuiz Capitulino if (fd < 0) { 63111d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 63211d0f125SLuiz Capitulino } 63311d0f125SLuiz Capitulino 63411d0f125SLuiz Capitulino ret = read(fd, buf, sizeof(buf)-1); 63511d0f125SLuiz Capitulino if (ret <= 0) { 63611d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 63711d0f125SLuiz Capitulino } 63811d0f125SLuiz Capitulino buf[ret] = '\0'; 63911d0f125SLuiz Capitulino 64011d0f125SLuiz Capitulino if (strstr(buf, sysfile_str)) { 64111d0f125SLuiz Capitulino _exit(SUSPEND_SUPPORTED); 64211d0f125SLuiz Capitulino } 64311d0f125SLuiz Capitulino 64411d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 64511d0f125SLuiz Capitulino } 64611d0f125SLuiz Capitulino 64711d0f125SLuiz Capitulino g_free(pmutils_path); 64811d0f125SLuiz Capitulino 64911d0f125SLuiz Capitulino if (pid < 0) { 650dc8764f0SLuiz Capitulino goto undef_err; 65111d0f125SLuiz Capitulino } 65211d0f125SLuiz Capitulino 653dc8764f0SLuiz Capitulino do { 654dc8764f0SLuiz Capitulino rpid = waitpid(pid, &status, 0); 655dc8764f0SLuiz Capitulino } while (rpid == -1 && errno == EINTR); 656dc8764f0SLuiz Capitulino if (rpid == pid && WIFEXITED(status)) { 657dc8764f0SLuiz Capitulino switch (WEXITSTATUS(status)) { 658dc8764f0SLuiz Capitulino case SUSPEND_SUPPORTED: 659dc8764f0SLuiz Capitulino return; 660dc8764f0SLuiz Capitulino case SUSPEND_NOT_SUPPORTED: 66111d0f125SLuiz Capitulino error_set(err, QERR_UNSUPPORTED); 662dc8764f0SLuiz Capitulino return; 663dc8764f0SLuiz Capitulino default: 664dc8764f0SLuiz Capitulino goto undef_err; 665dc8764f0SLuiz Capitulino } 666dc8764f0SLuiz Capitulino } 66711d0f125SLuiz Capitulino 668dc8764f0SLuiz Capitulino undef_err: 669dc8764f0SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 67011d0f125SLuiz Capitulino } 67111d0f125SLuiz Capitulino 67211d0f125SLuiz Capitulino static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, 67311d0f125SLuiz Capitulino Error **err) 67411d0f125SLuiz Capitulino { 67511d0f125SLuiz Capitulino char *pmutils_path; 676dc8764f0SLuiz Capitulino pid_t rpid, pid; 677dc8764f0SLuiz Capitulino int status; 67811d0f125SLuiz Capitulino 67911d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 68011d0f125SLuiz Capitulino 68111d0f125SLuiz Capitulino pid = fork(); 68211d0f125SLuiz Capitulino if (pid == 0) { 68311d0f125SLuiz Capitulino /* child */ 68411d0f125SLuiz Capitulino int fd; 68511d0f125SLuiz Capitulino 68611d0f125SLuiz Capitulino setsid(); 68711d0f125SLuiz Capitulino reopen_fd_to_null(0); 68811d0f125SLuiz Capitulino reopen_fd_to_null(1); 68911d0f125SLuiz Capitulino reopen_fd_to_null(2); 69011d0f125SLuiz Capitulino 69111d0f125SLuiz Capitulino if (pmutils_path) { 69211d0f125SLuiz Capitulino execle(pmutils_path, pmutils_bin, NULL, environ); 69311d0f125SLuiz Capitulino } 69411d0f125SLuiz Capitulino 69511d0f125SLuiz Capitulino /* 69611d0f125SLuiz Capitulino * If we get here either pm-utils is not installed or execle() has 69711d0f125SLuiz Capitulino * failed. Let's try the manual method if the caller wants it. 69811d0f125SLuiz Capitulino */ 69911d0f125SLuiz Capitulino 70011d0f125SLuiz Capitulino if (!sysfile_str) { 70111d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 70211d0f125SLuiz Capitulino } 70311d0f125SLuiz Capitulino 70411d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_WRONLY); 70511d0f125SLuiz Capitulino if (fd < 0) { 70611d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 70711d0f125SLuiz Capitulino } 70811d0f125SLuiz Capitulino 70911d0f125SLuiz Capitulino if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) { 71011d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 71111d0f125SLuiz Capitulino } 71211d0f125SLuiz Capitulino 71311d0f125SLuiz Capitulino _exit(EXIT_SUCCESS); 71411d0f125SLuiz Capitulino } 71511d0f125SLuiz Capitulino 71611d0f125SLuiz Capitulino g_free(pmutils_path); 71711d0f125SLuiz Capitulino 71811d0f125SLuiz Capitulino if (pid < 0) { 719dc8764f0SLuiz Capitulino goto exit_err; 720dc8764f0SLuiz Capitulino } 721dc8764f0SLuiz Capitulino 722dc8764f0SLuiz Capitulino do { 723dc8764f0SLuiz Capitulino rpid = waitpid(pid, &status, 0); 724dc8764f0SLuiz Capitulino } while (rpid == -1 && errno == EINTR); 725dc8764f0SLuiz Capitulino if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { 72611d0f125SLuiz Capitulino return; 72711d0f125SLuiz Capitulino } 728dc8764f0SLuiz Capitulino 729dc8764f0SLuiz Capitulino exit_err: 730dc8764f0SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 73111d0f125SLuiz Capitulino } 73211d0f125SLuiz Capitulino 73311d0f125SLuiz Capitulino void qmp_guest_suspend_disk(Error **err) 73411d0f125SLuiz Capitulino { 73511d0f125SLuiz Capitulino bios_supports_mode("pm-is-supported", "--hibernate", "disk", err); 73611d0f125SLuiz Capitulino if (error_is_set(err)) { 73711d0f125SLuiz Capitulino return; 73811d0f125SLuiz Capitulino } 73911d0f125SLuiz Capitulino 74011d0f125SLuiz Capitulino guest_suspend("pm-hibernate", "disk", err); 74111d0f125SLuiz Capitulino } 74211d0f125SLuiz Capitulino 743fbf42210SLuiz Capitulino void qmp_guest_suspend_ram(Error **err) 744fbf42210SLuiz Capitulino { 745fbf42210SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend", "mem", err); 746fbf42210SLuiz Capitulino if (error_is_set(err)) { 747fbf42210SLuiz Capitulino return; 748fbf42210SLuiz Capitulino } 749fbf42210SLuiz Capitulino 750fbf42210SLuiz Capitulino guest_suspend("pm-suspend", "mem", err); 751fbf42210SLuiz Capitulino } 752fbf42210SLuiz Capitulino 75395f4f404SLuiz Capitulino void qmp_guest_suspend_hybrid(Error **err) 75495f4f404SLuiz Capitulino { 75595f4f404SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err); 75695f4f404SLuiz Capitulino if (error_is_set(err)) { 75795f4f404SLuiz Capitulino return; 75895f4f404SLuiz Capitulino } 75995f4f404SLuiz Capitulino 76095f4f404SLuiz Capitulino guest_suspend("pm-suspend-hybrid", NULL, err); 76195f4f404SLuiz Capitulino } 76295f4f404SLuiz Capitulino 7633424fc9fSMichal Privoznik static GuestNetworkInterfaceList * 7643424fc9fSMichal Privoznik guest_find_interface(GuestNetworkInterfaceList *head, 7653424fc9fSMichal Privoznik const char *name) 7663424fc9fSMichal Privoznik { 7673424fc9fSMichal Privoznik for (; head; head = head->next) { 7683424fc9fSMichal Privoznik if (strcmp(head->value->name, name) == 0) { 7693424fc9fSMichal Privoznik break; 7703424fc9fSMichal Privoznik } 7713424fc9fSMichal Privoznik } 7723424fc9fSMichal Privoznik 7733424fc9fSMichal Privoznik return head; 7743424fc9fSMichal Privoznik } 7753424fc9fSMichal Privoznik 7763424fc9fSMichal Privoznik /* 7773424fc9fSMichal Privoznik * Build information about guest interfaces 7783424fc9fSMichal Privoznik */ 7793424fc9fSMichal Privoznik GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 7803424fc9fSMichal Privoznik { 7813424fc9fSMichal Privoznik GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; 7823424fc9fSMichal Privoznik struct ifaddrs *ifap, *ifa; 7833424fc9fSMichal Privoznik char err_msg[512]; 7843424fc9fSMichal Privoznik 7853424fc9fSMichal Privoznik if (getifaddrs(&ifap) < 0) { 7863424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 7873424fc9fSMichal Privoznik "getifaddrs failed: %s", strerror(errno)); 7883424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 7893424fc9fSMichal Privoznik goto error; 7903424fc9fSMichal Privoznik } 7913424fc9fSMichal Privoznik 7923424fc9fSMichal Privoznik for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 7933424fc9fSMichal Privoznik GuestNetworkInterfaceList *info; 7943424fc9fSMichal Privoznik GuestIpAddressList **address_list = NULL, *address_item = NULL; 7953424fc9fSMichal Privoznik char addr4[INET_ADDRSTRLEN]; 7963424fc9fSMichal Privoznik char addr6[INET6_ADDRSTRLEN]; 7973424fc9fSMichal Privoznik int sock; 7983424fc9fSMichal Privoznik struct ifreq ifr; 7993424fc9fSMichal Privoznik unsigned char *mac_addr; 8003424fc9fSMichal Privoznik void *p; 8013424fc9fSMichal Privoznik 8023424fc9fSMichal Privoznik g_debug("Processing %s interface", ifa->ifa_name); 8033424fc9fSMichal Privoznik 8043424fc9fSMichal Privoznik info = guest_find_interface(head, ifa->ifa_name); 8053424fc9fSMichal Privoznik 8063424fc9fSMichal Privoznik if (!info) { 8073424fc9fSMichal Privoznik info = g_malloc0(sizeof(*info)); 8083424fc9fSMichal Privoznik info->value = g_malloc0(sizeof(*info->value)); 8093424fc9fSMichal Privoznik info->value->name = g_strdup(ifa->ifa_name); 8103424fc9fSMichal Privoznik 8113424fc9fSMichal Privoznik if (!cur_item) { 8123424fc9fSMichal Privoznik head = cur_item = info; 8133424fc9fSMichal Privoznik } else { 8143424fc9fSMichal Privoznik cur_item->next = info; 8153424fc9fSMichal Privoznik cur_item = info; 8163424fc9fSMichal Privoznik } 8173424fc9fSMichal Privoznik } 8183424fc9fSMichal Privoznik 8193424fc9fSMichal Privoznik if (!info->value->has_hardware_address && 8203424fc9fSMichal Privoznik ifa->ifa_flags & SIOCGIFHWADDR) { 8213424fc9fSMichal Privoznik /* we haven't obtained HW address yet */ 8223424fc9fSMichal Privoznik sock = socket(PF_INET, SOCK_STREAM, 0); 8233424fc9fSMichal Privoznik if (sock == -1) { 8243424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8253424fc9fSMichal Privoznik "failed to create socket: %s", strerror(errno)); 8263424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8273424fc9fSMichal Privoznik goto error; 8283424fc9fSMichal Privoznik } 8293424fc9fSMichal Privoznik 8303424fc9fSMichal Privoznik memset(&ifr, 0, sizeof(ifr)); 8311ab516edSJim Meyering pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name); 8323424fc9fSMichal Privoznik if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { 8333424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 834a31f0531SJim Meyering "failed to get MAC address of %s: %s", 8353424fc9fSMichal Privoznik ifa->ifa_name, 8363424fc9fSMichal Privoznik strerror(errno)); 8373424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8383424fc9fSMichal Privoznik goto error; 8393424fc9fSMichal Privoznik } 8403424fc9fSMichal Privoznik 8413424fc9fSMichal Privoznik mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; 8423424fc9fSMichal Privoznik 8433424fc9fSMichal Privoznik if (asprintf(&info->value->hardware_address, 8443424fc9fSMichal Privoznik "%02x:%02x:%02x:%02x:%02x:%02x", 8453424fc9fSMichal Privoznik (int) mac_addr[0], (int) mac_addr[1], 8463424fc9fSMichal Privoznik (int) mac_addr[2], (int) mac_addr[3], 8473424fc9fSMichal Privoznik (int) mac_addr[4], (int) mac_addr[5]) == -1) { 8483424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8493424fc9fSMichal Privoznik "failed to format MAC: %s", strerror(errno)); 8503424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8513424fc9fSMichal Privoznik goto error; 8523424fc9fSMichal Privoznik } 8533424fc9fSMichal Privoznik 8543424fc9fSMichal Privoznik info->value->has_hardware_address = true; 8553424fc9fSMichal Privoznik close(sock); 8563424fc9fSMichal Privoznik } 8573424fc9fSMichal Privoznik 8583424fc9fSMichal Privoznik if (ifa->ifa_addr && 8593424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET) { 8603424fc9fSMichal Privoznik /* interface with IPv4 address */ 8613424fc9fSMichal Privoznik address_item = g_malloc0(sizeof(*address_item)); 8623424fc9fSMichal Privoznik address_item->value = g_malloc0(sizeof(*address_item->value)); 8633424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; 8643424fc9fSMichal Privoznik if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { 8653424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8663424fc9fSMichal Privoznik "inet_ntop failed : %s", strerror(errno)); 8673424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8683424fc9fSMichal Privoznik goto error; 8693424fc9fSMichal Privoznik } 8703424fc9fSMichal Privoznik 8713424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr4); 8723424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; 8733424fc9fSMichal Privoznik 8743424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 8753424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 8763424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 8773424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; 8783424fc9fSMichal Privoznik address_item->value->prefix = ctpop32(((uint32_t *) p)[0]); 8793424fc9fSMichal Privoznik } 8803424fc9fSMichal Privoznik } else if (ifa->ifa_addr && 8813424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET6) { 8823424fc9fSMichal Privoznik /* interface with IPv6 address */ 8833424fc9fSMichal Privoznik address_item = g_malloc0(sizeof(*address_item)); 8843424fc9fSMichal Privoznik address_item->value = g_malloc0(sizeof(*address_item->value)); 8853424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 8863424fc9fSMichal Privoznik if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { 8873424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8883424fc9fSMichal Privoznik "inet_ntop failed : %s", strerror(errno)); 8893424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8903424fc9fSMichal Privoznik goto error; 8913424fc9fSMichal Privoznik } 8923424fc9fSMichal Privoznik 8933424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr6); 8943424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; 8953424fc9fSMichal Privoznik 8963424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 8973424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 8983424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 8993424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 9003424fc9fSMichal Privoznik address_item->value->prefix = 9013424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[0]) + 9023424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[1]) + 9033424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[2]) + 9043424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[3]); 9053424fc9fSMichal Privoznik } 9063424fc9fSMichal Privoznik } 9073424fc9fSMichal Privoznik 9083424fc9fSMichal Privoznik if (!address_item) { 9093424fc9fSMichal Privoznik continue; 9103424fc9fSMichal Privoznik } 9113424fc9fSMichal Privoznik 9123424fc9fSMichal Privoznik address_list = &info->value->ip_addresses; 9133424fc9fSMichal Privoznik 9143424fc9fSMichal Privoznik while (*address_list && (*address_list)->next) { 9153424fc9fSMichal Privoznik address_list = &(*address_list)->next; 9163424fc9fSMichal Privoznik } 9173424fc9fSMichal Privoznik 9183424fc9fSMichal Privoznik if (!*address_list) { 9193424fc9fSMichal Privoznik *address_list = address_item; 9203424fc9fSMichal Privoznik } else { 9213424fc9fSMichal Privoznik (*address_list)->next = address_item; 9223424fc9fSMichal Privoznik } 9233424fc9fSMichal Privoznik 9243424fc9fSMichal Privoznik info->value->has_ip_addresses = true; 9253424fc9fSMichal Privoznik 9263424fc9fSMichal Privoznik 9273424fc9fSMichal Privoznik } 9283424fc9fSMichal Privoznik 9293424fc9fSMichal Privoznik freeifaddrs(ifap); 9303424fc9fSMichal Privoznik return head; 9313424fc9fSMichal Privoznik 9323424fc9fSMichal Privoznik error: 9333424fc9fSMichal Privoznik freeifaddrs(ifap); 9343424fc9fSMichal Privoznik qapi_free_GuestNetworkInterfaceList(head); 9353424fc9fSMichal Privoznik return NULL; 9363424fc9fSMichal Privoznik } 9373424fc9fSMichal Privoznik 938e72c3f2eSMichael Roth #else /* defined(__linux__) */ 939e72c3f2eSMichael Roth 940e72c3f2eSMichael Roth void qmp_guest_suspend_disk(Error **err) 941e72c3f2eSMichael Roth { 942e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 943e72c3f2eSMichael Roth } 944e72c3f2eSMichael Roth 945e72c3f2eSMichael Roth void qmp_guest_suspend_ram(Error **err) 946e72c3f2eSMichael Roth { 947e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 948e72c3f2eSMichael Roth } 949e72c3f2eSMichael Roth 950e72c3f2eSMichael Roth void qmp_guest_suspend_hybrid(Error **err) 951e72c3f2eSMichael Roth { 952e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 953e72c3f2eSMichael Roth } 954e72c3f2eSMichael Roth 955e72c3f2eSMichael Roth GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 956e72c3f2eSMichael Roth { 957e72c3f2eSMichael Roth error_set(errp, QERR_UNSUPPORTED); 958e72c3f2eSMichael Roth return NULL; 959e72c3f2eSMichael Roth } 960e72c3f2eSMichael Roth 961e72c3f2eSMichael Roth #endif 962e72c3f2eSMichael Roth 963d35d4cb5SMichael Roth #if !defined(CONFIG_FSFREEZE) 964d35d4cb5SMichael Roth 965d35d4cb5SMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 966d35d4cb5SMichael Roth { 967d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 968d35d4cb5SMichael Roth 969d35d4cb5SMichael Roth return 0; 970d35d4cb5SMichael Roth } 971d35d4cb5SMichael Roth 972d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 973d35d4cb5SMichael Roth { 974d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 975d35d4cb5SMichael Roth 976d35d4cb5SMichael Roth return 0; 977d35d4cb5SMichael Roth } 978d35d4cb5SMichael Roth 979d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 980d35d4cb5SMichael Roth { 981d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 982d35d4cb5SMichael Roth 983d35d4cb5SMichael Roth return 0; 984d35d4cb5SMichael Roth } 985eab5fd59SPaolo Bonzini #endif /* CONFIG_FSFREEZE */ 986d35d4cb5SMichael Roth 987eab5fd59SPaolo Bonzini #if !defined(CONFIG_FSTRIM) 988eab5fd59SPaolo Bonzini void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) 989eab5fd59SPaolo Bonzini { 990eab5fd59SPaolo Bonzini error_set(err, QERR_UNSUPPORTED); 991eab5fd59SPaolo Bonzini } 992d35d4cb5SMichael Roth #endif 993d35d4cb5SMichael Roth 994c216e5adSMichael Roth /* register init/cleanup routines for stateful command groups */ 995c216e5adSMichael Roth void ga_command_state_init(GAState *s, GACommandState *cs) 996c216e5adSMichael Roth { 997c216e5adSMichael Roth #if defined(CONFIG_FSFREEZE) 998f22d85e9SMichael Roth ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); 999c216e5adSMichael Roth #endif 1000c216e5adSMichael Roth ga_command_state_add(cs, guest_file_init, NULL); 1001c216e5adSMichael Roth } 1002