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" 211de7afc9SPaolo Bonzini #include "qemu/queue.h" 221de7afc9SPaolo 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 49*d220a6dfSLuiz Capitulino static void ga_wait_child(pid_t pid, int *status, Error **err) 50*d220a6dfSLuiz Capitulino { 51*d220a6dfSLuiz Capitulino pid_t rpid; 52*d220a6dfSLuiz Capitulino 53*d220a6dfSLuiz Capitulino *status = 0; 54*d220a6dfSLuiz Capitulino 55*d220a6dfSLuiz Capitulino do { 56*d220a6dfSLuiz Capitulino rpid = waitpid(pid, status, 0); 57*d220a6dfSLuiz Capitulino } while (rpid == -1 && errno == EINTR); 58*d220a6dfSLuiz Capitulino 59*d220a6dfSLuiz Capitulino if (rpid == -1) { 60*d220a6dfSLuiz Capitulino error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid); 61*d220a6dfSLuiz Capitulino return; 62*d220a6dfSLuiz Capitulino } 63*d220a6dfSLuiz Capitulino 64*d220a6dfSLuiz Capitulino g_assert(rpid == pid); 65*d220a6dfSLuiz Capitulino } 66*d220a6dfSLuiz Capitulino 67c216e5adSMichael Roth void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) 68c216e5adSMichael Roth { 69c216e5adSMichael Roth const char *shutdown_flag; 70*d220a6dfSLuiz Capitulino Error *local_err = NULL; 71*d220a6dfSLuiz Capitulino pid_t pid; 723674838cSLuiz Capitulino int status; 73c216e5adSMichael Roth 74c216e5adSMichael Roth slog("guest-shutdown called, mode: %s", mode); 75c216e5adSMichael Roth if (!has_mode || strcmp(mode, "powerdown") == 0) { 76c216e5adSMichael Roth shutdown_flag = "-P"; 77c216e5adSMichael Roth } else if (strcmp(mode, "halt") == 0) { 78c216e5adSMichael Roth shutdown_flag = "-H"; 79c216e5adSMichael Roth } else if (strcmp(mode, "reboot") == 0) { 80c216e5adSMichael Roth shutdown_flag = "-r"; 81c216e5adSMichael Roth } else { 82*d220a6dfSLuiz Capitulino error_setg(err, 83*d220a6dfSLuiz Capitulino "mode is invalid (valid values are: halt|powerdown|reboot"); 84c216e5adSMichael Roth return; 85c216e5adSMichael Roth } 86c216e5adSMichael Roth 87d5dd3498SLuiz Capitulino pid = fork(); 88d5dd3498SLuiz Capitulino if (pid == 0) { 89c216e5adSMichael Roth /* child, start the shutdown */ 90c216e5adSMichael Roth setsid(); 913674838cSLuiz Capitulino reopen_fd_to_null(0); 923674838cSLuiz Capitulino reopen_fd_to_null(1); 933674838cSLuiz Capitulino reopen_fd_to_null(2); 94c216e5adSMichael Roth 953674838cSLuiz Capitulino execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0", 963674838cSLuiz Capitulino "hypervisor initiated shutdown", (char*)NULL, environ); 973674838cSLuiz Capitulino _exit(EXIT_FAILURE); 98d5dd3498SLuiz Capitulino } else if (pid < 0) { 99*d220a6dfSLuiz Capitulino error_setg_errno(err, errno, "failed to create child process"); 100d5dd3498SLuiz Capitulino return; 101d5dd3498SLuiz Capitulino } 102d5dd3498SLuiz Capitulino 103*d220a6dfSLuiz Capitulino ga_wait_child(pid, &status, &local_err); 104*d220a6dfSLuiz Capitulino if (error_is_set(&local_err)) { 105*d220a6dfSLuiz Capitulino error_propagate(err, local_err); 106*d220a6dfSLuiz Capitulino return; 107*d220a6dfSLuiz Capitulino } 108*d220a6dfSLuiz Capitulino 109*d220a6dfSLuiz Capitulino if (!WIFEXITED(status)) { 110*d220a6dfSLuiz Capitulino error_setg(err, "child process has terminated abnormally"); 111*d220a6dfSLuiz Capitulino return; 112*d220a6dfSLuiz Capitulino } 113*d220a6dfSLuiz Capitulino 114*d220a6dfSLuiz Capitulino if (WEXITSTATUS(status)) { 115*d220a6dfSLuiz Capitulino error_setg(err, "child process has failed to shutdown"); 116*d220a6dfSLuiz Capitulino return; 117*d220a6dfSLuiz Capitulino } 118*d220a6dfSLuiz Capitulino 119*d220a6dfSLuiz Capitulino /* succeded */ 120c216e5adSMichael Roth } 121c216e5adSMichael Roth 122c216e5adSMichael Roth typedef struct GuestFileHandle { 123c216e5adSMichael Roth uint64_t id; 124c216e5adSMichael Roth FILE *fh; 125c216e5adSMichael Roth QTAILQ_ENTRY(GuestFileHandle) next; 126c216e5adSMichael Roth } GuestFileHandle; 127c216e5adSMichael Roth 128c216e5adSMichael Roth static struct { 129c216e5adSMichael Roth QTAILQ_HEAD(, GuestFileHandle) filehandles; 130c216e5adSMichael Roth } guest_file_state; 131c216e5adSMichael Roth 132c216e5adSMichael Roth static void guest_file_handle_add(FILE *fh) 133c216e5adSMichael Roth { 134c216e5adSMichael Roth GuestFileHandle *gfh; 135c216e5adSMichael Roth 136c216e5adSMichael Roth gfh = g_malloc0(sizeof(GuestFileHandle)); 137c216e5adSMichael Roth gfh->id = fileno(fh); 138c216e5adSMichael Roth gfh->fh = fh; 139c216e5adSMichael Roth QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); 140c216e5adSMichael Roth } 141c216e5adSMichael Roth 142a9de6d01SLuiz Capitulino static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) 143c216e5adSMichael Roth { 144c216e5adSMichael Roth GuestFileHandle *gfh; 145c216e5adSMichael Roth 146c216e5adSMichael Roth QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) 147c216e5adSMichael Roth { 148c216e5adSMichael Roth if (gfh->id == id) { 149c216e5adSMichael Roth return gfh; 150c216e5adSMichael Roth } 151c216e5adSMichael Roth } 152c216e5adSMichael Roth 153a9de6d01SLuiz Capitulino error_setg(err, "handle '%" PRId64 "' has not been found", id); 154c216e5adSMichael Roth return NULL; 155c216e5adSMichael Roth } 156c216e5adSMichael Roth 157c216e5adSMichael Roth int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err) 158c216e5adSMichael Roth { 159c216e5adSMichael Roth FILE *fh; 160c216e5adSMichael Roth int fd; 161c216e5adSMichael Roth int64_t ret = -1; 162c216e5adSMichael Roth 163c216e5adSMichael Roth if (!has_mode) { 164c216e5adSMichael Roth mode = "r"; 165c216e5adSMichael Roth } 166c216e5adSMichael Roth slog("guest-file-open called, filepath: %s, mode: %s", path, mode); 167c216e5adSMichael Roth fh = fopen(path, mode); 168c216e5adSMichael Roth if (!fh) { 169db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')", 170db3edb66SLuiz Capitulino path, mode); 171c216e5adSMichael Roth return -1; 172c216e5adSMichael Roth } 173c216e5adSMichael Roth 174c216e5adSMichael Roth /* set fd non-blocking to avoid common use cases (like reading from a 175c216e5adSMichael Roth * named pipe) from hanging the agent 176c216e5adSMichael Roth */ 177c216e5adSMichael Roth fd = fileno(fh); 178c216e5adSMichael Roth ret = fcntl(fd, F_GETFL); 179c216e5adSMichael Roth ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK); 180c216e5adSMichael Roth if (ret == -1) { 181db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to make file '%s' non-blocking", 182db3edb66SLuiz Capitulino path); 183c216e5adSMichael Roth fclose(fh); 184c216e5adSMichael Roth return -1; 185c216e5adSMichael Roth } 186c216e5adSMichael Roth 187c216e5adSMichael Roth guest_file_handle_add(fh); 188c216e5adSMichael Roth slog("guest-file-open, handle: %d", fd); 189c216e5adSMichael Roth return fd; 190c216e5adSMichael Roth } 191c216e5adSMichael Roth 192c216e5adSMichael Roth void qmp_guest_file_close(int64_t handle, Error **err) 193c216e5adSMichael Roth { 194a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 195c216e5adSMichael Roth int ret; 196c216e5adSMichael Roth 197c216e5adSMichael Roth slog("guest-file-close called, handle: %ld", handle); 198c216e5adSMichael Roth if (!gfh) { 199c216e5adSMichael Roth return; 200c216e5adSMichael Roth } 201c216e5adSMichael Roth 202c216e5adSMichael Roth ret = fclose(gfh->fh); 2033ac4b7c5SLuiz Capitulino if (ret == EOF) { 204db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to close handle"); 205c216e5adSMichael Roth return; 206c216e5adSMichael Roth } 207c216e5adSMichael Roth 208c216e5adSMichael Roth QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next); 209c216e5adSMichael Roth g_free(gfh); 210c216e5adSMichael Roth } 211c216e5adSMichael Roth 212c216e5adSMichael Roth struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, 213c216e5adSMichael Roth int64_t count, Error **err) 214c216e5adSMichael Roth { 215a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 216c216e5adSMichael Roth GuestFileRead *read_data = NULL; 217c216e5adSMichael Roth guchar *buf; 218c216e5adSMichael Roth FILE *fh; 219c216e5adSMichael Roth size_t read_count; 220c216e5adSMichael Roth 221c216e5adSMichael Roth if (!gfh) { 222c216e5adSMichael Roth return NULL; 223c216e5adSMichael Roth } 224c216e5adSMichael Roth 225c216e5adSMichael Roth if (!has_count) { 226c216e5adSMichael Roth count = QGA_READ_COUNT_DEFAULT; 227c216e5adSMichael Roth } else if (count < 0) { 228db3edb66SLuiz Capitulino error_setg(err, "value '%" PRId64 "' is invalid for argument count", 229db3edb66SLuiz Capitulino count); 230c216e5adSMichael Roth return NULL; 231c216e5adSMichael Roth } 232c216e5adSMichael Roth 233c216e5adSMichael Roth fh = gfh->fh; 234c216e5adSMichael Roth buf = g_malloc0(count+1); 235c216e5adSMichael Roth read_count = fread(buf, 1, count, fh); 236c216e5adSMichael Roth if (ferror(fh)) { 237db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to read file"); 238c216e5adSMichael Roth slog("guest-file-read failed, handle: %ld", handle); 239c216e5adSMichael Roth } else { 240c216e5adSMichael Roth buf[read_count] = 0; 241c216e5adSMichael Roth read_data = g_malloc0(sizeof(GuestFileRead)); 242c216e5adSMichael Roth read_data->count = read_count; 243c216e5adSMichael Roth read_data->eof = feof(fh); 244c216e5adSMichael Roth if (read_count) { 245c216e5adSMichael Roth read_data->buf_b64 = g_base64_encode(buf, read_count); 246c216e5adSMichael Roth } 247c216e5adSMichael Roth } 248c216e5adSMichael Roth g_free(buf); 249c216e5adSMichael Roth clearerr(fh); 250c216e5adSMichael Roth 251c216e5adSMichael Roth return read_data; 252c216e5adSMichael Roth } 253c216e5adSMichael Roth 254c216e5adSMichael Roth GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, 255c216e5adSMichael Roth bool has_count, int64_t count, Error **err) 256c216e5adSMichael Roth { 257c216e5adSMichael Roth GuestFileWrite *write_data = NULL; 258c216e5adSMichael Roth guchar *buf; 259c216e5adSMichael Roth gsize buf_len; 260c216e5adSMichael Roth int write_count; 261a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 262c216e5adSMichael Roth FILE *fh; 263c216e5adSMichael Roth 264c216e5adSMichael Roth if (!gfh) { 265c216e5adSMichael Roth return NULL; 266c216e5adSMichael Roth } 267c216e5adSMichael Roth 268c216e5adSMichael Roth fh = gfh->fh; 269c216e5adSMichael Roth buf = g_base64_decode(buf_b64, &buf_len); 270c216e5adSMichael Roth 271c216e5adSMichael Roth if (!has_count) { 272c216e5adSMichael Roth count = buf_len; 273c216e5adSMichael Roth } else if (count < 0 || count > buf_len) { 274db3edb66SLuiz Capitulino error_setg(err, "value '%" PRId64 "' is invalid for argument count", 275db3edb66SLuiz Capitulino count); 276c216e5adSMichael Roth g_free(buf); 277c216e5adSMichael Roth return NULL; 278c216e5adSMichael Roth } 279c216e5adSMichael Roth 280c216e5adSMichael Roth write_count = fwrite(buf, 1, count, fh); 281c216e5adSMichael Roth if (ferror(fh)) { 282db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to write to file"); 283c216e5adSMichael Roth slog("guest-file-write failed, handle: %ld", handle); 284c216e5adSMichael Roth } else { 285c216e5adSMichael Roth write_data = g_malloc0(sizeof(GuestFileWrite)); 286c216e5adSMichael Roth write_data->count = write_count; 287c216e5adSMichael Roth write_data->eof = feof(fh); 288c216e5adSMichael Roth } 289c216e5adSMichael Roth g_free(buf); 290c216e5adSMichael Roth clearerr(fh); 291c216e5adSMichael Roth 292c216e5adSMichael Roth return write_data; 293c216e5adSMichael Roth } 294c216e5adSMichael Roth 295c216e5adSMichael Roth struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, 296c216e5adSMichael Roth int64_t whence, Error **err) 297c216e5adSMichael Roth { 298a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 299c216e5adSMichael Roth GuestFileSeek *seek_data = NULL; 300c216e5adSMichael Roth FILE *fh; 301c216e5adSMichael Roth int ret; 302c216e5adSMichael Roth 303c216e5adSMichael Roth if (!gfh) { 304c216e5adSMichael Roth return NULL; 305c216e5adSMichael Roth } 306c216e5adSMichael Roth 307c216e5adSMichael Roth fh = gfh->fh; 308c216e5adSMichael Roth ret = fseek(fh, offset, whence); 309c216e5adSMichael Roth if (ret == -1) { 310db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to seek file"); 311c216e5adSMichael Roth } else { 312c216e5adSMichael Roth seek_data = g_malloc0(sizeof(GuestFileRead)); 313c216e5adSMichael Roth seek_data->position = ftell(fh); 314c216e5adSMichael Roth seek_data->eof = feof(fh); 315c216e5adSMichael Roth } 316c216e5adSMichael Roth clearerr(fh); 317c216e5adSMichael Roth 318c216e5adSMichael Roth return seek_data; 319c216e5adSMichael Roth } 320c216e5adSMichael Roth 321c216e5adSMichael Roth void qmp_guest_file_flush(int64_t handle, Error **err) 322c216e5adSMichael Roth { 323a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 324c216e5adSMichael Roth FILE *fh; 325c216e5adSMichael Roth int ret; 326c216e5adSMichael Roth 327c216e5adSMichael Roth if (!gfh) { 328c216e5adSMichael Roth return; 329c216e5adSMichael Roth } 330c216e5adSMichael Roth 331c216e5adSMichael Roth fh = gfh->fh; 332c216e5adSMichael Roth ret = fflush(fh); 333c216e5adSMichael Roth if (ret == EOF) { 334db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to flush file"); 335c216e5adSMichael Roth } 336c216e5adSMichael Roth } 337c216e5adSMichael Roth 338c216e5adSMichael Roth static void guest_file_init(void) 339c216e5adSMichael Roth { 340c216e5adSMichael Roth QTAILQ_INIT(&guest_file_state.filehandles); 341c216e5adSMichael Roth } 342c216e5adSMichael Roth 343e72c3f2eSMichael Roth /* linux-specific implementations. avoid this if at all possible. */ 344e72c3f2eSMichael Roth #if defined(__linux__) 345e72c3f2eSMichael Roth 346eab5fd59SPaolo Bonzini #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) 347af02203fSPaolo Bonzini typedef struct FsMount { 348c216e5adSMichael Roth char *dirname; 349c216e5adSMichael Roth char *devtype; 350af02203fSPaolo Bonzini QTAILQ_ENTRY(FsMount) next; 351af02203fSPaolo Bonzini } FsMount; 352c216e5adSMichael Roth 353af02203fSPaolo Bonzini typedef QTAILQ_HEAD(, FsMount) FsMountList; 3549e8aded4SMichael Roth 355af02203fSPaolo Bonzini static void free_fs_mount_list(FsMountList *mounts) 356c216e5adSMichael Roth { 357af02203fSPaolo Bonzini FsMount *mount, *temp; 358c216e5adSMichael Roth 3599e8aded4SMichael Roth if (!mounts) { 3609e8aded4SMichael Roth return; 3619e8aded4SMichael Roth } 3629e8aded4SMichael Roth 3639e8aded4SMichael Roth QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) { 3649e8aded4SMichael Roth QTAILQ_REMOVE(mounts, mount, next); 365c216e5adSMichael Roth g_free(mount->dirname); 366c216e5adSMichael Roth g_free(mount->devtype); 367c216e5adSMichael Roth g_free(mount); 368c216e5adSMichael Roth } 3699e8aded4SMichael Roth } 3709e8aded4SMichael Roth 3719e8aded4SMichael Roth /* 3729e8aded4SMichael Roth * Walk the mount table and build a list of local file systems 3739e8aded4SMichael Roth */ 374af02203fSPaolo Bonzini static int build_fs_mount_list(FsMountList *mounts) 3759e8aded4SMichael Roth { 3769e8aded4SMichael Roth struct mntent *ment; 377af02203fSPaolo Bonzini FsMount *mount; 3789e2fa418SMichael Roth char const *mtab = "/proc/self/mounts"; 3799e8aded4SMichael Roth FILE *fp; 380c216e5adSMichael Roth 381c216e5adSMichael Roth fp = setmntent(mtab, "r"); 382c216e5adSMichael Roth if (!fp) { 383c216e5adSMichael Roth g_warning("fsfreeze: unable to read mtab"); 384c216e5adSMichael Roth return -1; 385c216e5adSMichael Roth } 386c216e5adSMichael Roth 387c216e5adSMichael Roth while ((ment = getmntent(fp))) { 388c216e5adSMichael Roth /* 389c216e5adSMichael Roth * An entry which device name doesn't start with a '/' is 390c216e5adSMichael Roth * either a dummy file system or a network file system. 391c216e5adSMichael Roth * Add special handling for smbfs and cifs as is done by 392c216e5adSMichael Roth * coreutils as well. 393c216e5adSMichael Roth */ 394c216e5adSMichael Roth if ((ment->mnt_fsname[0] != '/') || 395c216e5adSMichael Roth (strcmp(ment->mnt_type, "smbfs") == 0) || 396c216e5adSMichael Roth (strcmp(ment->mnt_type, "cifs") == 0)) { 397c216e5adSMichael Roth continue; 398c216e5adSMichael Roth } 399c216e5adSMichael Roth 400af02203fSPaolo Bonzini mount = g_malloc0(sizeof(FsMount)); 401c216e5adSMichael Roth mount->dirname = g_strdup(ment->mnt_dir); 402c216e5adSMichael Roth mount->devtype = g_strdup(ment->mnt_type); 403c216e5adSMichael Roth 4049e8aded4SMichael Roth QTAILQ_INSERT_TAIL(mounts, mount, next); 405c216e5adSMichael Roth } 406c216e5adSMichael Roth 407c216e5adSMichael Roth endmntent(fp); 408c216e5adSMichael Roth 409c216e5adSMichael Roth return 0; 410c216e5adSMichael Roth } 411eab5fd59SPaolo Bonzini #endif 412eab5fd59SPaolo Bonzini 413eab5fd59SPaolo Bonzini #if defined(CONFIG_FSFREEZE) 414c216e5adSMichael Roth 415c216e5adSMichael Roth /* 416c216e5adSMichael Roth * Return status of freeze/thaw 417c216e5adSMichael Roth */ 418c216e5adSMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 419c216e5adSMichael Roth { 420f22d85e9SMichael Roth if (ga_is_frozen(ga_state)) { 421f22d85e9SMichael Roth return GUEST_FSFREEZE_STATUS_FROZEN; 422f22d85e9SMichael Roth } 423f22d85e9SMichael Roth 424f22d85e9SMichael Roth return GUEST_FSFREEZE_STATUS_THAWED; 425c216e5adSMichael Roth } 426c216e5adSMichael Roth 427c216e5adSMichael Roth /* 428c216e5adSMichael Roth * Walk list of mounted file systems in the guest, and freeze the ones which 429c216e5adSMichael Roth * are real local file systems. 430c216e5adSMichael Roth */ 431c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 432c216e5adSMichael Roth { 433c216e5adSMichael Roth int ret = 0, i = 0; 434af02203fSPaolo Bonzini FsMountList mounts; 435af02203fSPaolo Bonzini struct FsMount *mount; 436c216e5adSMichael Roth int fd; 437c216e5adSMichael Roth char err_msg[512]; 438c216e5adSMichael Roth 439c216e5adSMichael Roth slog("guest-fsfreeze called"); 440c216e5adSMichael Roth 4419e8aded4SMichael Roth QTAILQ_INIT(&mounts); 442af02203fSPaolo Bonzini ret = build_fs_mount_list(&mounts); 443c216e5adSMichael Roth if (ret < 0) { 444c216e5adSMichael Roth return ret; 445c216e5adSMichael Roth } 446c216e5adSMichael Roth 447c216e5adSMichael Roth /* cannot risk guest agent blocking itself on a write in this state */ 448f22d85e9SMichael Roth ga_set_frozen(ga_state); 449c216e5adSMichael Roth 4509e8aded4SMichael Roth QTAILQ_FOREACH(mount, &mounts, next) { 451c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 452c216e5adSMichael Roth if (fd == -1) { 4539e8aded4SMichael Roth sprintf(err_msg, "failed to open %s, %s", mount->dirname, 4549e8aded4SMichael Roth strerror(errno)); 455c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 456c216e5adSMichael Roth goto error; 457c216e5adSMichael Roth } 458c216e5adSMichael Roth 459c216e5adSMichael Roth /* we try to cull filesytems we know won't work in advance, but other 460c216e5adSMichael Roth * filesytems may not implement fsfreeze for less obvious reasons. 4619e8aded4SMichael Roth * these will report EOPNOTSUPP. we simply ignore these when tallying 4629e8aded4SMichael Roth * the number of frozen filesystems. 4639e8aded4SMichael Roth * 4649e8aded4SMichael Roth * any other error means a failure to freeze a filesystem we 4659e8aded4SMichael Roth * expect to be freezable, so return an error in those cases 4669e8aded4SMichael Roth * and return system to thawed state. 467c216e5adSMichael Roth */ 468c216e5adSMichael Roth ret = ioctl(fd, FIFREEZE); 4699e8aded4SMichael Roth if (ret == -1) { 4709e8aded4SMichael Roth if (errno != EOPNOTSUPP) { 4719e8aded4SMichael Roth sprintf(err_msg, "failed to freeze %s, %s", 4729e8aded4SMichael Roth mount->dirname, strerror(errno)); 473c216e5adSMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 474c216e5adSMichael Roth close(fd); 475c216e5adSMichael Roth goto error; 476c216e5adSMichael Roth } 4779e8aded4SMichael Roth } else { 478c216e5adSMichael Roth i++; 479c216e5adSMichael Roth } 4809e8aded4SMichael Roth close(fd); 4819e8aded4SMichael Roth } 482c216e5adSMichael Roth 483af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 484c216e5adSMichael Roth return i; 485c216e5adSMichael Roth 486c216e5adSMichael Roth error: 487af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 488c216e5adSMichael Roth qmp_guest_fsfreeze_thaw(NULL); 489c216e5adSMichael Roth return 0; 490c216e5adSMichael Roth } 491c216e5adSMichael Roth 492c216e5adSMichael Roth /* 493c216e5adSMichael Roth * Walk list of frozen file systems in the guest, and thaw them. 494c216e5adSMichael Roth */ 495c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 496c216e5adSMichael Roth { 497c216e5adSMichael Roth int ret; 498af02203fSPaolo Bonzini FsMountList mounts; 499af02203fSPaolo Bonzini FsMount *mount; 5009e8aded4SMichael Roth int fd, i = 0, logged; 501c216e5adSMichael Roth 5029e8aded4SMichael Roth QTAILQ_INIT(&mounts); 503af02203fSPaolo Bonzini ret = build_fs_mount_list(&mounts); 5049e8aded4SMichael Roth if (ret) { 5059e8aded4SMichael Roth error_set(err, QERR_QGA_COMMAND_FAILED, 5069e8aded4SMichael Roth "failed to enumerate filesystems"); 5079e8aded4SMichael Roth return 0; 5089e8aded4SMichael Roth } 5099e8aded4SMichael Roth 5109e8aded4SMichael Roth QTAILQ_FOREACH(mount, &mounts, next) { 5119e8aded4SMichael Roth logged = false; 512c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 513c216e5adSMichael Roth if (fd == -1) { 514c216e5adSMichael Roth continue; 515c216e5adSMichael Roth } 5169e8aded4SMichael Roth /* we have no way of knowing whether a filesystem was actually unfrozen 5179e8aded4SMichael Roth * as a result of a successful call to FITHAW, only that if an error 5189e8aded4SMichael Roth * was returned the filesystem was *not* unfrozen by that particular 5199e8aded4SMichael Roth * call. 5209e8aded4SMichael Roth * 521a31f0531SJim Meyering * since multiple preceding FIFREEZEs require multiple calls to FITHAW 5229e8aded4SMichael Roth * to unfreeze, continuing issuing FITHAW until an error is returned, 5239e8aded4SMichael Roth * in which case either the filesystem is in an unfreezable state, or, 5249e8aded4SMichael Roth * more likely, it was thawed previously (and remains so afterward). 5259e8aded4SMichael Roth * 5269e8aded4SMichael Roth * also, since the most recent successful call is the one that did 5279e8aded4SMichael Roth * the actual unfreeze, we can use this to provide an accurate count 5289e8aded4SMichael Roth * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which 5299e8aded4SMichael Roth * may * be useful for determining whether a filesystem was unfrozen 5309e8aded4SMichael Roth * during the freeze/thaw phase by a process other than qemu-ga. 5319e8aded4SMichael Roth */ 5329e8aded4SMichael Roth do { 533c216e5adSMichael Roth ret = ioctl(fd, FITHAW); 5349e8aded4SMichael Roth if (ret == 0 && !logged) { 535c216e5adSMichael Roth i++; 5369e8aded4SMichael Roth logged = true; 5379e8aded4SMichael Roth } 5389e8aded4SMichael Roth } while (ret == 0); 5399e8aded4SMichael Roth close(fd); 540c216e5adSMichael Roth } 541c216e5adSMichael Roth 542f22d85e9SMichael Roth ga_unset_frozen(ga_state); 543af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 544c216e5adSMichael Roth return i; 545c216e5adSMichael Roth } 546c216e5adSMichael Roth 547c216e5adSMichael Roth static void guest_fsfreeze_cleanup(void) 548c216e5adSMichael Roth { 549c216e5adSMichael Roth int64_t ret; 550c216e5adSMichael Roth Error *err = NULL; 551c216e5adSMichael Roth 552f22d85e9SMichael Roth if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { 553c216e5adSMichael Roth ret = qmp_guest_fsfreeze_thaw(&err); 554c216e5adSMichael Roth if (ret < 0 || err) { 555c216e5adSMichael Roth slog("failed to clean up frozen filesystems"); 556c216e5adSMichael Roth } 557c216e5adSMichael Roth } 558c216e5adSMichael Roth } 559e72c3f2eSMichael Roth #endif /* CONFIG_FSFREEZE */ 560c216e5adSMichael Roth 561eab5fd59SPaolo Bonzini #if defined(CONFIG_FSTRIM) 562eab5fd59SPaolo Bonzini /* 563eab5fd59SPaolo Bonzini * Walk list of mounted file systems in the guest, and trim them. 564eab5fd59SPaolo Bonzini */ 565eab5fd59SPaolo Bonzini void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) 566eab5fd59SPaolo Bonzini { 567eab5fd59SPaolo Bonzini int ret = 0; 568eab5fd59SPaolo Bonzini FsMountList mounts; 569eab5fd59SPaolo Bonzini struct FsMount *mount; 570eab5fd59SPaolo Bonzini int fd; 571eab5fd59SPaolo Bonzini char err_msg[512]; 572eab5fd59SPaolo Bonzini struct fstrim_range r = { 573eab5fd59SPaolo Bonzini .start = 0, 574eab5fd59SPaolo Bonzini .len = -1, 575eab5fd59SPaolo Bonzini .minlen = has_minimum ? minimum : 0, 576eab5fd59SPaolo Bonzini }; 577eab5fd59SPaolo Bonzini 578eab5fd59SPaolo Bonzini slog("guest-fstrim called"); 579eab5fd59SPaolo Bonzini 580eab5fd59SPaolo Bonzini QTAILQ_INIT(&mounts); 581eab5fd59SPaolo Bonzini ret = build_fs_mount_list(&mounts); 582eab5fd59SPaolo Bonzini if (ret < 0) { 583eab5fd59SPaolo Bonzini return; 584eab5fd59SPaolo Bonzini } 585eab5fd59SPaolo Bonzini 586eab5fd59SPaolo Bonzini QTAILQ_FOREACH(mount, &mounts, next) { 587eab5fd59SPaolo Bonzini fd = qemu_open(mount->dirname, O_RDONLY); 588eab5fd59SPaolo Bonzini if (fd == -1) { 589eab5fd59SPaolo Bonzini sprintf(err_msg, "failed to open %s, %s", mount->dirname, 590eab5fd59SPaolo Bonzini strerror(errno)); 591eab5fd59SPaolo Bonzini error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 592eab5fd59SPaolo Bonzini goto error; 593eab5fd59SPaolo Bonzini } 594eab5fd59SPaolo Bonzini 595eab5fd59SPaolo Bonzini /* We try to cull filesytems we know won't work in advance, but other 596eab5fd59SPaolo Bonzini * filesytems may not implement fstrim for less obvious reasons. These 597eab5fd59SPaolo Bonzini * will report EOPNOTSUPP; we simply ignore these errors. Any other 598eab5fd59SPaolo Bonzini * error means an unexpected error, so return it in those cases. In 599eab5fd59SPaolo Bonzini * some other cases ENOTTY will be reported (e.g. CD-ROMs). 600eab5fd59SPaolo Bonzini */ 601eab5fd59SPaolo Bonzini ret = ioctl(fd, FITRIM, &r); 602eab5fd59SPaolo Bonzini if (ret == -1) { 603eab5fd59SPaolo Bonzini if (errno != ENOTTY && errno != EOPNOTSUPP) { 604eab5fd59SPaolo Bonzini sprintf(err_msg, "failed to trim %s, %s", 605eab5fd59SPaolo Bonzini mount->dirname, strerror(errno)); 606eab5fd59SPaolo Bonzini error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); 607eab5fd59SPaolo Bonzini close(fd); 608eab5fd59SPaolo Bonzini goto error; 609eab5fd59SPaolo Bonzini } 610eab5fd59SPaolo Bonzini } 611eab5fd59SPaolo Bonzini close(fd); 612eab5fd59SPaolo Bonzini } 613eab5fd59SPaolo Bonzini 614eab5fd59SPaolo Bonzini error: 615eab5fd59SPaolo Bonzini free_fs_mount_list(&mounts); 616eab5fd59SPaolo Bonzini } 617eab5fd59SPaolo Bonzini #endif /* CONFIG_FSTRIM */ 618eab5fd59SPaolo Bonzini 619eab5fd59SPaolo Bonzini 62011d0f125SLuiz Capitulino #define LINUX_SYS_STATE_FILE "/sys/power/state" 62111d0f125SLuiz Capitulino #define SUSPEND_SUPPORTED 0 62211d0f125SLuiz Capitulino #define SUSPEND_NOT_SUPPORTED 1 62311d0f125SLuiz Capitulino 62411d0f125SLuiz Capitulino static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, 62511d0f125SLuiz Capitulino const char *sysfile_str, Error **err) 62611d0f125SLuiz Capitulino { 62711d0f125SLuiz Capitulino char *pmutils_path; 628dc8764f0SLuiz Capitulino pid_t pid, rpid; 629dc8764f0SLuiz Capitulino int status; 63011d0f125SLuiz Capitulino 63111d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 63211d0f125SLuiz Capitulino 63311d0f125SLuiz Capitulino pid = fork(); 63411d0f125SLuiz Capitulino if (!pid) { 635dc8764f0SLuiz Capitulino char buf[32]; /* hopefully big enough */ 636dc8764f0SLuiz Capitulino ssize_t ret; 637dc8764f0SLuiz 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, pmutils_arg, 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(SUSPEND_NOT_SUPPORTED); 65511d0f125SLuiz Capitulino } 65611d0f125SLuiz Capitulino 65711d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); 65811d0f125SLuiz Capitulino if (fd < 0) { 65911d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 66011d0f125SLuiz Capitulino } 66111d0f125SLuiz Capitulino 66211d0f125SLuiz Capitulino ret = read(fd, buf, sizeof(buf)-1); 66311d0f125SLuiz Capitulino if (ret <= 0) { 66411d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 66511d0f125SLuiz Capitulino } 66611d0f125SLuiz Capitulino buf[ret] = '\0'; 66711d0f125SLuiz Capitulino 66811d0f125SLuiz Capitulino if (strstr(buf, sysfile_str)) { 66911d0f125SLuiz Capitulino _exit(SUSPEND_SUPPORTED); 67011d0f125SLuiz Capitulino } 67111d0f125SLuiz Capitulino 67211d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 67311d0f125SLuiz Capitulino } 67411d0f125SLuiz Capitulino 67511d0f125SLuiz Capitulino g_free(pmutils_path); 67611d0f125SLuiz Capitulino 67711d0f125SLuiz Capitulino if (pid < 0) { 678dc8764f0SLuiz Capitulino goto undef_err; 67911d0f125SLuiz Capitulino } 68011d0f125SLuiz Capitulino 681dc8764f0SLuiz Capitulino do { 682dc8764f0SLuiz Capitulino rpid = waitpid(pid, &status, 0); 683dc8764f0SLuiz Capitulino } while (rpid == -1 && errno == EINTR); 684dc8764f0SLuiz Capitulino if (rpid == pid && WIFEXITED(status)) { 685dc8764f0SLuiz Capitulino switch (WEXITSTATUS(status)) { 686dc8764f0SLuiz Capitulino case SUSPEND_SUPPORTED: 687dc8764f0SLuiz Capitulino return; 688dc8764f0SLuiz Capitulino case SUSPEND_NOT_SUPPORTED: 68911d0f125SLuiz Capitulino error_set(err, QERR_UNSUPPORTED); 690dc8764f0SLuiz Capitulino return; 691dc8764f0SLuiz Capitulino default: 692dc8764f0SLuiz Capitulino goto undef_err; 693dc8764f0SLuiz Capitulino } 694dc8764f0SLuiz Capitulino } 69511d0f125SLuiz Capitulino 696dc8764f0SLuiz Capitulino undef_err: 697dc8764f0SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 69811d0f125SLuiz Capitulino } 69911d0f125SLuiz Capitulino 70011d0f125SLuiz Capitulino static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, 70111d0f125SLuiz Capitulino Error **err) 70211d0f125SLuiz Capitulino { 70311d0f125SLuiz Capitulino char *pmutils_path; 704dc8764f0SLuiz Capitulino pid_t rpid, pid; 705dc8764f0SLuiz Capitulino int status; 70611d0f125SLuiz Capitulino 70711d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 70811d0f125SLuiz Capitulino 70911d0f125SLuiz Capitulino pid = fork(); 71011d0f125SLuiz Capitulino if (pid == 0) { 71111d0f125SLuiz Capitulino /* child */ 71211d0f125SLuiz Capitulino int fd; 71311d0f125SLuiz Capitulino 71411d0f125SLuiz Capitulino setsid(); 71511d0f125SLuiz Capitulino reopen_fd_to_null(0); 71611d0f125SLuiz Capitulino reopen_fd_to_null(1); 71711d0f125SLuiz Capitulino reopen_fd_to_null(2); 71811d0f125SLuiz Capitulino 71911d0f125SLuiz Capitulino if (pmutils_path) { 72011d0f125SLuiz Capitulino execle(pmutils_path, pmutils_bin, NULL, environ); 72111d0f125SLuiz Capitulino } 72211d0f125SLuiz Capitulino 72311d0f125SLuiz Capitulino /* 72411d0f125SLuiz Capitulino * If we get here either pm-utils is not installed or execle() has 72511d0f125SLuiz Capitulino * failed. Let's try the manual method if the caller wants it. 72611d0f125SLuiz Capitulino */ 72711d0f125SLuiz Capitulino 72811d0f125SLuiz Capitulino if (!sysfile_str) { 72911d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 73011d0f125SLuiz Capitulino } 73111d0f125SLuiz Capitulino 73211d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_WRONLY); 73311d0f125SLuiz Capitulino if (fd < 0) { 73411d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 73511d0f125SLuiz Capitulino } 73611d0f125SLuiz Capitulino 73711d0f125SLuiz Capitulino if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) { 73811d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 73911d0f125SLuiz Capitulino } 74011d0f125SLuiz Capitulino 74111d0f125SLuiz Capitulino _exit(EXIT_SUCCESS); 74211d0f125SLuiz Capitulino } 74311d0f125SLuiz Capitulino 74411d0f125SLuiz Capitulino g_free(pmutils_path); 74511d0f125SLuiz Capitulino 74611d0f125SLuiz Capitulino if (pid < 0) { 747dc8764f0SLuiz Capitulino goto exit_err; 748dc8764f0SLuiz Capitulino } 749dc8764f0SLuiz Capitulino 750dc8764f0SLuiz Capitulino do { 751dc8764f0SLuiz Capitulino rpid = waitpid(pid, &status, 0); 752dc8764f0SLuiz Capitulino } while (rpid == -1 && errno == EINTR); 753dc8764f0SLuiz Capitulino if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { 75411d0f125SLuiz Capitulino return; 75511d0f125SLuiz Capitulino } 756dc8764f0SLuiz Capitulino 757dc8764f0SLuiz Capitulino exit_err: 758dc8764f0SLuiz Capitulino error_set(err, QERR_UNDEFINED_ERROR); 75911d0f125SLuiz Capitulino } 76011d0f125SLuiz Capitulino 76111d0f125SLuiz Capitulino void qmp_guest_suspend_disk(Error **err) 76211d0f125SLuiz Capitulino { 76311d0f125SLuiz Capitulino bios_supports_mode("pm-is-supported", "--hibernate", "disk", err); 76411d0f125SLuiz Capitulino if (error_is_set(err)) { 76511d0f125SLuiz Capitulino return; 76611d0f125SLuiz Capitulino } 76711d0f125SLuiz Capitulino 76811d0f125SLuiz Capitulino guest_suspend("pm-hibernate", "disk", err); 76911d0f125SLuiz Capitulino } 77011d0f125SLuiz Capitulino 771fbf42210SLuiz Capitulino void qmp_guest_suspend_ram(Error **err) 772fbf42210SLuiz Capitulino { 773fbf42210SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend", "mem", err); 774fbf42210SLuiz Capitulino if (error_is_set(err)) { 775fbf42210SLuiz Capitulino return; 776fbf42210SLuiz Capitulino } 777fbf42210SLuiz Capitulino 778fbf42210SLuiz Capitulino guest_suspend("pm-suspend", "mem", err); 779fbf42210SLuiz Capitulino } 780fbf42210SLuiz Capitulino 78195f4f404SLuiz Capitulino void qmp_guest_suspend_hybrid(Error **err) 78295f4f404SLuiz Capitulino { 78395f4f404SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err); 78495f4f404SLuiz Capitulino if (error_is_set(err)) { 78595f4f404SLuiz Capitulino return; 78695f4f404SLuiz Capitulino } 78795f4f404SLuiz Capitulino 78895f4f404SLuiz Capitulino guest_suspend("pm-suspend-hybrid", NULL, err); 78995f4f404SLuiz Capitulino } 79095f4f404SLuiz Capitulino 7913424fc9fSMichal Privoznik static GuestNetworkInterfaceList * 7923424fc9fSMichal Privoznik guest_find_interface(GuestNetworkInterfaceList *head, 7933424fc9fSMichal Privoznik const char *name) 7943424fc9fSMichal Privoznik { 7953424fc9fSMichal Privoznik for (; head; head = head->next) { 7963424fc9fSMichal Privoznik if (strcmp(head->value->name, name) == 0) { 7973424fc9fSMichal Privoznik break; 7983424fc9fSMichal Privoznik } 7993424fc9fSMichal Privoznik } 8003424fc9fSMichal Privoznik 8013424fc9fSMichal Privoznik return head; 8023424fc9fSMichal Privoznik } 8033424fc9fSMichal Privoznik 8043424fc9fSMichal Privoznik /* 8053424fc9fSMichal Privoznik * Build information about guest interfaces 8063424fc9fSMichal Privoznik */ 8073424fc9fSMichal Privoznik GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 8083424fc9fSMichal Privoznik { 8093424fc9fSMichal Privoznik GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; 8103424fc9fSMichal Privoznik struct ifaddrs *ifap, *ifa; 8113424fc9fSMichal Privoznik char err_msg[512]; 8123424fc9fSMichal Privoznik 8133424fc9fSMichal Privoznik if (getifaddrs(&ifap) < 0) { 8143424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8153424fc9fSMichal Privoznik "getifaddrs failed: %s", strerror(errno)); 8163424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8173424fc9fSMichal Privoznik goto error; 8183424fc9fSMichal Privoznik } 8193424fc9fSMichal Privoznik 8203424fc9fSMichal Privoznik for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 8213424fc9fSMichal Privoznik GuestNetworkInterfaceList *info; 8223424fc9fSMichal Privoznik GuestIpAddressList **address_list = NULL, *address_item = NULL; 8233424fc9fSMichal Privoznik char addr4[INET_ADDRSTRLEN]; 8243424fc9fSMichal Privoznik char addr6[INET6_ADDRSTRLEN]; 8253424fc9fSMichal Privoznik int sock; 8263424fc9fSMichal Privoznik struct ifreq ifr; 8273424fc9fSMichal Privoznik unsigned char *mac_addr; 8283424fc9fSMichal Privoznik void *p; 8293424fc9fSMichal Privoznik 8303424fc9fSMichal Privoznik g_debug("Processing %s interface", ifa->ifa_name); 8313424fc9fSMichal Privoznik 8323424fc9fSMichal Privoznik info = guest_find_interface(head, ifa->ifa_name); 8333424fc9fSMichal Privoznik 8343424fc9fSMichal Privoznik if (!info) { 8353424fc9fSMichal Privoznik info = g_malloc0(sizeof(*info)); 8363424fc9fSMichal Privoznik info->value = g_malloc0(sizeof(*info->value)); 8373424fc9fSMichal Privoznik info->value->name = g_strdup(ifa->ifa_name); 8383424fc9fSMichal Privoznik 8393424fc9fSMichal Privoznik if (!cur_item) { 8403424fc9fSMichal Privoznik head = cur_item = info; 8413424fc9fSMichal Privoznik } else { 8423424fc9fSMichal Privoznik cur_item->next = info; 8433424fc9fSMichal Privoznik cur_item = info; 8443424fc9fSMichal Privoznik } 8453424fc9fSMichal Privoznik } 8463424fc9fSMichal Privoznik 8473424fc9fSMichal Privoznik if (!info->value->has_hardware_address && 8483424fc9fSMichal Privoznik ifa->ifa_flags & SIOCGIFHWADDR) { 8493424fc9fSMichal Privoznik /* we haven't obtained HW address yet */ 8503424fc9fSMichal Privoznik sock = socket(PF_INET, SOCK_STREAM, 0); 8513424fc9fSMichal Privoznik if (sock == -1) { 8523424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8533424fc9fSMichal Privoznik "failed to create socket: %s", strerror(errno)); 8543424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8553424fc9fSMichal Privoznik goto error; 8563424fc9fSMichal Privoznik } 8573424fc9fSMichal Privoznik 8583424fc9fSMichal Privoznik memset(&ifr, 0, sizeof(ifr)); 8591ab516edSJim Meyering pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name); 8603424fc9fSMichal Privoznik if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { 8613424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 862a31f0531SJim Meyering "failed to get MAC address of %s: %s", 8633424fc9fSMichal Privoznik ifa->ifa_name, 8643424fc9fSMichal Privoznik strerror(errno)); 8653424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8663424fc9fSMichal Privoznik goto error; 8673424fc9fSMichal Privoznik } 8683424fc9fSMichal Privoznik 8693424fc9fSMichal Privoznik mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; 8703424fc9fSMichal Privoznik 8713424fc9fSMichal Privoznik if (asprintf(&info->value->hardware_address, 8723424fc9fSMichal Privoznik "%02x:%02x:%02x:%02x:%02x:%02x", 8733424fc9fSMichal Privoznik (int) mac_addr[0], (int) mac_addr[1], 8743424fc9fSMichal Privoznik (int) mac_addr[2], (int) mac_addr[3], 8753424fc9fSMichal Privoznik (int) mac_addr[4], (int) mac_addr[5]) == -1) { 8763424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8773424fc9fSMichal Privoznik "failed to format MAC: %s", strerror(errno)); 8783424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8793424fc9fSMichal Privoznik goto error; 8803424fc9fSMichal Privoznik } 8813424fc9fSMichal Privoznik 8823424fc9fSMichal Privoznik info->value->has_hardware_address = true; 8833424fc9fSMichal Privoznik close(sock); 8843424fc9fSMichal Privoznik } 8853424fc9fSMichal Privoznik 8863424fc9fSMichal Privoznik if (ifa->ifa_addr && 8873424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET) { 8883424fc9fSMichal Privoznik /* interface with IPv4 address */ 8893424fc9fSMichal Privoznik address_item = g_malloc0(sizeof(*address_item)); 8903424fc9fSMichal Privoznik address_item->value = g_malloc0(sizeof(*address_item->value)); 8913424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; 8923424fc9fSMichal Privoznik if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { 8933424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 8943424fc9fSMichal Privoznik "inet_ntop failed : %s", strerror(errno)); 8953424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 8963424fc9fSMichal Privoznik goto error; 8973424fc9fSMichal Privoznik } 8983424fc9fSMichal Privoznik 8993424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr4); 9003424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; 9013424fc9fSMichal Privoznik 9023424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 9033424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 9043424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 9053424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; 9063424fc9fSMichal Privoznik address_item->value->prefix = ctpop32(((uint32_t *) p)[0]); 9073424fc9fSMichal Privoznik } 9083424fc9fSMichal Privoznik } else if (ifa->ifa_addr && 9093424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET6) { 9103424fc9fSMichal Privoznik /* interface with IPv6 address */ 9113424fc9fSMichal Privoznik address_item = g_malloc0(sizeof(*address_item)); 9123424fc9fSMichal Privoznik address_item->value = g_malloc0(sizeof(*address_item->value)); 9133424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 9143424fc9fSMichal Privoznik if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { 9153424fc9fSMichal Privoznik snprintf(err_msg, sizeof(err_msg), 9163424fc9fSMichal Privoznik "inet_ntop failed : %s", strerror(errno)); 9173424fc9fSMichal Privoznik error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); 9183424fc9fSMichal Privoznik goto error; 9193424fc9fSMichal Privoznik } 9203424fc9fSMichal Privoznik 9213424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr6); 9223424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; 9233424fc9fSMichal Privoznik 9243424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 9253424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 9263424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 9273424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 9283424fc9fSMichal Privoznik address_item->value->prefix = 9293424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[0]) + 9303424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[1]) + 9313424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[2]) + 9323424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[3]); 9333424fc9fSMichal Privoznik } 9343424fc9fSMichal Privoznik } 9353424fc9fSMichal Privoznik 9363424fc9fSMichal Privoznik if (!address_item) { 9373424fc9fSMichal Privoznik continue; 9383424fc9fSMichal Privoznik } 9393424fc9fSMichal Privoznik 9403424fc9fSMichal Privoznik address_list = &info->value->ip_addresses; 9413424fc9fSMichal Privoznik 9423424fc9fSMichal Privoznik while (*address_list && (*address_list)->next) { 9433424fc9fSMichal Privoznik address_list = &(*address_list)->next; 9443424fc9fSMichal Privoznik } 9453424fc9fSMichal Privoznik 9463424fc9fSMichal Privoznik if (!*address_list) { 9473424fc9fSMichal Privoznik *address_list = address_item; 9483424fc9fSMichal Privoznik } else { 9493424fc9fSMichal Privoznik (*address_list)->next = address_item; 9503424fc9fSMichal Privoznik } 9513424fc9fSMichal Privoznik 9523424fc9fSMichal Privoznik info->value->has_ip_addresses = true; 9533424fc9fSMichal Privoznik 9543424fc9fSMichal Privoznik 9553424fc9fSMichal Privoznik } 9563424fc9fSMichal Privoznik 9573424fc9fSMichal Privoznik freeifaddrs(ifap); 9583424fc9fSMichal Privoznik return head; 9593424fc9fSMichal Privoznik 9603424fc9fSMichal Privoznik error: 9613424fc9fSMichal Privoznik freeifaddrs(ifap); 9623424fc9fSMichal Privoznik qapi_free_GuestNetworkInterfaceList(head); 9633424fc9fSMichal Privoznik return NULL; 9643424fc9fSMichal Privoznik } 9653424fc9fSMichal Privoznik 966e72c3f2eSMichael Roth #else /* defined(__linux__) */ 967e72c3f2eSMichael Roth 968e72c3f2eSMichael Roth void qmp_guest_suspend_disk(Error **err) 969e72c3f2eSMichael Roth { 970e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 971e72c3f2eSMichael Roth } 972e72c3f2eSMichael Roth 973e72c3f2eSMichael Roth void qmp_guest_suspend_ram(Error **err) 974e72c3f2eSMichael Roth { 975e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 976e72c3f2eSMichael Roth } 977e72c3f2eSMichael Roth 978e72c3f2eSMichael Roth void qmp_guest_suspend_hybrid(Error **err) 979e72c3f2eSMichael Roth { 980e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 981e72c3f2eSMichael Roth } 982e72c3f2eSMichael Roth 983e72c3f2eSMichael Roth GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 984e72c3f2eSMichael Roth { 985e72c3f2eSMichael Roth error_set(errp, QERR_UNSUPPORTED); 986e72c3f2eSMichael Roth return NULL; 987e72c3f2eSMichael Roth } 988e72c3f2eSMichael Roth 989e72c3f2eSMichael Roth #endif 990e72c3f2eSMichael Roth 991d35d4cb5SMichael Roth #if !defined(CONFIG_FSFREEZE) 992d35d4cb5SMichael Roth 993d35d4cb5SMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 994d35d4cb5SMichael Roth { 995d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 996d35d4cb5SMichael Roth 997d35d4cb5SMichael Roth return 0; 998d35d4cb5SMichael Roth } 999d35d4cb5SMichael Roth 1000d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 1001d35d4cb5SMichael Roth { 1002d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 1003d35d4cb5SMichael Roth 1004d35d4cb5SMichael Roth return 0; 1005d35d4cb5SMichael Roth } 1006d35d4cb5SMichael Roth 1007d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 1008d35d4cb5SMichael Roth { 1009d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 1010d35d4cb5SMichael Roth 1011d35d4cb5SMichael Roth return 0; 1012d35d4cb5SMichael Roth } 1013eab5fd59SPaolo Bonzini #endif /* CONFIG_FSFREEZE */ 1014d35d4cb5SMichael Roth 1015eab5fd59SPaolo Bonzini #if !defined(CONFIG_FSTRIM) 1016eab5fd59SPaolo Bonzini void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) 1017eab5fd59SPaolo Bonzini { 1018eab5fd59SPaolo Bonzini error_set(err, QERR_UNSUPPORTED); 1019eab5fd59SPaolo Bonzini } 1020d35d4cb5SMichael Roth #endif 1021d35d4cb5SMichael Roth 1022c216e5adSMichael Roth /* register init/cleanup routines for stateful command groups */ 1023c216e5adSMichael Roth void ga_command_state_init(GAState *s, GACommandState *cs) 1024c216e5adSMichael Roth { 1025c216e5adSMichael Roth #if defined(CONFIG_FSFREEZE) 1026f22d85e9SMichael Roth ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); 1027c216e5adSMichael Roth #endif 1028c216e5adSMichael Roth ga_command_state_add(cs, guest_file_init, NULL); 1029c216e5adSMichael Roth } 1030