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 49d220a6dfSLuiz Capitulino static void ga_wait_child(pid_t pid, int *status, Error **err) 50d220a6dfSLuiz Capitulino { 51d220a6dfSLuiz Capitulino pid_t rpid; 52d220a6dfSLuiz Capitulino 53d220a6dfSLuiz Capitulino *status = 0; 54d220a6dfSLuiz Capitulino 55d220a6dfSLuiz Capitulino do { 56d220a6dfSLuiz Capitulino rpid = waitpid(pid, status, 0); 57d220a6dfSLuiz Capitulino } while (rpid == -1 && errno == EINTR); 58d220a6dfSLuiz Capitulino 59d220a6dfSLuiz Capitulino if (rpid == -1) { 60d220a6dfSLuiz Capitulino error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid); 61d220a6dfSLuiz Capitulino return; 62d220a6dfSLuiz Capitulino } 63d220a6dfSLuiz Capitulino 64d220a6dfSLuiz Capitulino g_assert(rpid == pid); 65d220a6dfSLuiz Capitulino } 66d220a6dfSLuiz Capitulino 67c216e5adSMichael Roth void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) 68c216e5adSMichael Roth { 69c216e5adSMichael Roth const char *shutdown_flag; 70d220a6dfSLuiz Capitulino Error *local_err = NULL; 71d220a6dfSLuiz 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 { 82d220a6dfSLuiz Capitulino error_setg(err, 83d220a6dfSLuiz 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) { 99d220a6dfSLuiz Capitulino error_setg_errno(err, errno, "failed to create child process"); 100d5dd3498SLuiz Capitulino return; 101d5dd3498SLuiz Capitulino } 102d5dd3498SLuiz Capitulino 103d220a6dfSLuiz Capitulino ga_wait_child(pid, &status, &local_err); 104d220a6dfSLuiz Capitulino if (error_is_set(&local_err)) { 105d220a6dfSLuiz Capitulino error_propagate(err, local_err); 106d220a6dfSLuiz Capitulino return; 107d220a6dfSLuiz Capitulino } 108d220a6dfSLuiz Capitulino 109d220a6dfSLuiz Capitulino if (!WIFEXITED(status)) { 110d220a6dfSLuiz Capitulino error_setg(err, "child process has terminated abnormally"); 111d220a6dfSLuiz Capitulino return; 112d220a6dfSLuiz Capitulino } 113d220a6dfSLuiz Capitulino 114d220a6dfSLuiz Capitulino if (WEXITSTATUS(status)) { 115d220a6dfSLuiz Capitulino error_setg(err, "child process has failed to shutdown"); 116d220a6dfSLuiz Capitulino return; 117d220a6dfSLuiz Capitulino } 118d220a6dfSLuiz Capitulino 119d220a6dfSLuiz 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 132*39097dafSMichael Roth static int64_t guest_file_handle_add(FILE *fh, Error **errp) 133c216e5adSMichael Roth { 134c216e5adSMichael Roth GuestFileHandle *gfh; 135*39097dafSMichael Roth int64_t handle; 136*39097dafSMichael Roth 137*39097dafSMichael Roth handle = ga_get_fd_handle(ga_state, errp); 138*39097dafSMichael Roth if (error_is_set(errp)) { 139*39097dafSMichael Roth return 0; 140*39097dafSMichael Roth } 141c216e5adSMichael Roth 142c216e5adSMichael Roth gfh = g_malloc0(sizeof(GuestFileHandle)); 143*39097dafSMichael Roth gfh->id = handle; 144c216e5adSMichael Roth gfh->fh = fh; 145c216e5adSMichael Roth QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); 146*39097dafSMichael Roth 147*39097dafSMichael Roth return handle; 148c216e5adSMichael Roth } 149c216e5adSMichael Roth 150a9de6d01SLuiz Capitulino static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) 151c216e5adSMichael Roth { 152c216e5adSMichael Roth GuestFileHandle *gfh; 153c216e5adSMichael Roth 154c216e5adSMichael Roth QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) 155c216e5adSMichael Roth { 156c216e5adSMichael Roth if (gfh->id == id) { 157c216e5adSMichael Roth return gfh; 158c216e5adSMichael Roth } 159c216e5adSMichael Roth } 160c216e5adSMichael Roth 161a9de6d01SLuiz Capitulino error_setg(err, "handle '%" PRId64 "' has not been found", id); 162c216e5adSMichael Roth return NULL; 163c216e5adSMichael Roth } 164c216e5adSMichael Roth 165c216e5adSMichael Roth int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err) 166c216e5adSMichael Roth { 167c216e5adSMichael Roth FILE *fh; 168c216e5adSMichael Roth int fd; 169*39097dafSMichael Roth int64_t ret = -1, handle; 170c216e5adSMichael Roth 171c216e5adSMichael Roth if (!has_mode) { 172c216e5adSMichael Roth mode = "r"; 173c216e5adSMichael Roth } 174c216e5adSMichael Roth slog("guest-file-open called, filepath: %s, mode: %s", path, mode); 175c216e5adSMichael Roth fh = fopen(path, mode); 176c216e5adSMichael Roth if (!fh) { 177db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')", 178db3edb66SLuiz Capitulino path, mode); 179c216e5adSMichael Roth return -1; 180c216e5adSMichael Roth } 181c216e5adSMichael Roth 182c216e5adSMichael Roth /* set fd non-blocking to avoid common use cases (like reading from a 183c216e5adSMichael Roth * named pipe) from hanging the agent 184c216e5adSMichael Roth */ 185c216e5adSMichael Roth fd = fileno(fh); 186c216e5adSMichael Roth ret = fcntl(fd, F_GETFL); 187c216e5adSMichael Roth ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK); 188c216e5adSMichael Roth if (ret == -1) { 189db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to make file '%s' non-blocking", 190db3edb66SLuiz Capitulino path); 191c216e5adSMichael Roth fclose(fh); 192c216e5adSMichael Roth return -1; 193c216e5adSMichael Roth } 194c216e5adSMichael Roth 195*39097dafSMichael Roth handle = guest_file_handle_add(fh, err); 196*39097dafSMichael Roth if (error_is_set(err)) { 197*39097dafSMichael Roth fclose(fh); 198*39097dafSMichael Roth return -1; 199*39097dafSMichael Roth } 200*39097dafSMichael Roth 201*39097dafSMichael Roth slog("guest-file-open, handle: %d", handle); 202*39097dafSMichael Roth return handle; 203c216e5adSMichael Roth } 204c216e5adSMichael Roth 205c216e5adSMichael Roth void qmp_guest_file_close(int64_t handle, Error **err) 206c216e5adSMichael Roth { 207a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 208c216e5adSMichael Roth int ret; 209c216e5adSMichael Roth 210c216e5adSMichael Roth slog("guest-file-close called, handle: %ld", handle); 211c216e5adSMichael Roth if (!gfh) { 212c216e5adSMichael Roth return; 213c216e5adSMichael Roth } 214c216e5adSMichael Roth 215c216e5adSMichael Roth ret = fclose(gfh->fh); 2163ac4b7c5SLuiz Capitulino if (ret == EOF) { 217db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to close handle"); 218c216e5adSMichael Roth return; 219c216e5adSMichael Roth } 220c216e5adSMichael Roth 221c216e5adSMichael Roth QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next); 222c216e5adSMichael Roth g_free(gfh); 223c216e5adSMichael Roth } 224c216e5adSMichael Roth 225c216e5adSMichael Roth struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, 226c216e5adSMichael Roth int64_t count, Error **err) 227c216e5adSMichael Roth { 228a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 229c216e5adSMichael Roth GuestFileRead *read_data = NULL; 230c216e5adSMichael Roth guchar *buf; 231c216e5adSMichael Roth FILE *fh; 232c216e5adSMichael Roth size_t read_count; 233c216e5adSMichael Roth 234c216e5adSMichael Roth if (!gfh) { 235c216e5adSMichael Roth return NULL; 236c216e5adSMichael Roth } 237c216e5adSMichael Roth 238c216e5adSMichael Roth if (!has_count) { 239c216e5adSMichael Roth count = QGA_READ_COUNT_DEFAULT; 240c216e5adSMichael Roth } else if (count < 0) { 241db3edb66SLuiz Capitulino error_setg(err, "value '%" PRId64 "' is invalid for argument count", 242db3edb66SLuiz Capitulino count); 243c216e5adSMichael Roth return NULL; 244c216e5adSMichael Roth } 245c216e5adSMichael Roth 246c216e5adSMichael Roth fh = gfh->fh; 247c216e5adSMichael Roth buf = g_malloc0(count+1); 248c216e5adSMichael Roth read_count = fread(buf, 1, count, fh); 249c216e5adSMichael Roth if (ferror(fh)) { 250db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to read file"); 251c216e5adSMichael Roth slog("guest-file-read failed, handle: %ld", handle); 252c216e5adSMichael Roth } else { 253c216e5adSMichael Roth buf[read_count] = 0; 254c216e5adSMichael Roth read_data = g_malloc0(sizeof(GuestFileRead)); 255c216e5adSMichael Roth read_data->count = read_count; 256c216e5adSMichael Roth read_data->eof = feof(fh); 257c216e5adSMichael Roth if (read_count) { 258c216e5adSMichael Roth read_data->buf_b64 = g_base64_encode(buf, read_count); 259c216e5adSMichael Roth } 260c216e5adSMichael Roth } 261c216e5adSMichael Roth g_free(buf); 262c216e5adSMichael Roth clearerr(fh); 263c216e5adSMichael Roth 264c216e5adSMichael Roth return read_data; 265c216e5adSMichael Roth } 266c216e5adSMichael Roth 267c216e5adSMichael Roth GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, 268c216e5adSMichael Roth bool has_count, int64_t count, Error **err) 269c216e5adSMichael Roth { 270c216e5adSMichael Roth GuestFileWrite *write_data = NULL; 271c216e5adSMichael Roth guchar *buf; 272c216e5adSMichael Roth gsize buf_len; 273c216e5adSMichael Roth int write_count; 274a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 275c216e5adSMichael Roth FILE *fh; 276c216e5adSMichael Roth 277c216e5adSMichael Roth if (!gfh) { 278c216e5adSMichael Roth return NULL; 279c216e5adSMichael Roth } 280c216e5adSMichael Roth 281c216e5adSMichael Roth fh = gfh->fh; 282c216e5adSMichael Roth buf = g_base64_decode(buf_b64, &buf_len); 283c216e5adSMichael Roth 284c216e5adSMichael Roth if (!has_count) { 285c216e5adSMichael Roth count = buf_len; 286c216e5adSMichael Roth } else if (count < 0 || count > buf_len) { 287db3edb66SLuiz Capitulino error_setg(err, "value '%" PRId64 "' is invalid for argument count", 288db3edb66SLuiz Capitulino count); 289c216e5adSMichael Roth g_free(buf); 290c216e5adSMichael Roth return NULL; 291c216e5adSMichael Roth } 292c216e5adSMichael Roth 293c216e5adSMichael Roth write_count = fwrite(buf, 1, count, fh); 294c216e5adSMichael Roth if (ferror(fh)) { 295db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to write to file"); 296c216e5adSMichael Roth slog("guest-file-write failed, handle: %ld", handle); 297c216e5adSMichael Roth } else { 298c216e5adSMichael Roth write_data = g_malloc0(sizeof(GuestFileWrite)); 299c216e5adSMichael Roth write_data->count = write_count; 300c216e5adSMichael Roth write_data->eof = feof(fh); 301c216e5adSMichael Roth } 302c216e5adSMichael Roth g_free(buf); 303c216e5adSMichael Roth clearerr(fh); 304c216e5adSMichael Roth 305c216e5adSMichael Roth return write_data; 306c216e5adSMichael Roth } 307c216e5adSMichael Roth 308c216e5adSMichael Roth struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, 309c216e5adSMichael Roth int64_t whence, Error **err) 310c216e5adSMichael Roth { 311a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 312c216e5adSMichael Roth GuestFileSeek *seek_data = NULL; 313c216e5adSMichael Roth FILE *fh; 314c216e5adSMichael Roth int ret; 315c216e5adSMichael Roth 316c216e5adSMichael Roth if (!gfh) { 317c216e5adSMichael Roth return NULL; 318c216e5adSMichael Roth } 319c216e5adSMichael Roth 320c216e5adSMichael Roth fh = gfh->fh; 321c216e5adSMichael Roth ret = fseek(fh, offset, whence); 322c216e5adSMichael Roth if (ret == -1) { 323db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to seek file"); 324c216e5adSMichael Roth } else { 325c216e5adSMichael Roth seek_data = g_malloc0(sizeof(GuestFileRead)); 326c216e5adSMichael Roth seek_data->position = ftell(fh); 327c216e5adSMichael Roth seek_data->eof = feof(fh); 328c216e5adSMichael Roth } 329c216e5adSMichael Roth clearerr(fh); 330c216e5adSMichael Roth 331c216e5adSMichael Roth return seek_data; 332c216e5adSMichael Roth } 333c216e5adSMichael Roth 334c216e5adSMichael Roth void qmp_guest_file_flush(int64_t handle, Error **err) 335c216e5adSMichael Roth { 336a9de6d01SLuiz Capitulino GuestFileHandle *gfh = guest_file_handle_find(handle, err); 337c216e5adSMichael Roth FILE *fh; 338c216e5adSMichael Roth int ret; 339c216e5adSMichael Roth 340c216e5adSMichael Roth if (!gfh) { 341c216e5adSMichael Roth return; 342c216e5adSMichael Roth } 343c216e5adSMichael Roth 344c216e5adSMichael Roth fh = gfh->fh; 345c216e5adSMichael Roth ret = fflush(fh); 346c216e5adSMichael Roth if (ret == EOF) { 347db3edb66SLuiz Capitulino error_setg_errno(err, errno, "failed to flush file"); 348c216e5adSMichael Roth } 349c216e5adSMichael Roth } 350c216e5adSMichael Roth 351c216e5adSMichael Roth static void guest_file_init(void) 352c216e5adSMichael Roth { 353c216e5adSMichael Roth QTAILQ_INIT(&guest_file_state.filehandles); 354c216e5adSMichael Roth } 355c216e5adSMichael Roth 356e72c3f2eSMichael Roth /* linux-specific implementations. avoid this if at all possible. */ 357e72c3f2eSMichael Roth #if defined(__linux__) 358e72c3f2eSMichael Roth 359eab5fd59SPaolo Bonzini #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) 360af02203fSPaolo Bonzini typedef struct FsMount { 361c216e5adSMichael Roth char *dirname; 362c216e5adSMichael Roth char *devtype; 363af02203fSPaolo Bonzini QTAILQ_ENTRY(FsMount) next; 364af02203fSPaolo Bonzini } FsMount; 365c216e5adSMichael Roth 366af02203fSPaolo Bonzini typedef QTAILQ_HEAD(, FsMount) FsMountList; 3679e8aded4SMichael Roth 368af02203fSPaolo Bonzini static void free_fs_mount_list(FsMountList *mounts) 369c216e5adSMichael Roth { 370af02203fSPaolo Bonzini FsMount *mount, *temp; 371c216e5adSMichael Roth 3729e8aded4SMichael Roth if (!mounts) { 3739e8aded4SMichael Roth return; 3749e8aded4SMichael Roth } 3759e8aded4SMichael Roth 3769e8aded4SMichael Roth QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) { 3779e8aded4SMichael Roth QTAILQ_REMOVE(mounts, mount, next); 378c216e5adSMichael Roth g_free(mount->dirname); 379c216e5adSMichael Roth g_free(mount->devtype); 380c216e5adSMichael Roth g_free(mount); 381c216e5adSMichael Roth } 3829e8aded4SMichael Roth } 3839e8aded4SMichael Roth 3849e8aded4SMichael Roth /* 3859e8aded4SMichael Roth * Walk the mount table and build a list of local file systems 3869e8aded4SMichael Roth */ 387261551d1SLuiz Capitulino static void build_fs_mount_list(FsMountList *mounts, Error **err) 3889e8aded4SMichael Roth { 3899e8aded4SMichael Roth struct mntent *ment; 390af02203fSPaolo Bonzini FsMount *mount; 3919e2fa418SMichael Roth char const *mtab = "/proc/self/mounts"; 3929e8aded4SMichael Roth FILE *fp; 393c216e5adSMichael Roth 394c216e5adSMichael Roth fp = setmntent(mtab, "r"); 395c216e5adSMichael Roth if (!fp) { 396261551d1SLuiz Capitulino error_setg(err, "failed to open mtab file: '%s'", mtab); 397261551d1SLuiz Capitulino return; 398c216e5adSMichael Roth } 399c216e5adSMichael Roth 400c216e5adSMichael Roth while ((ment = getmntent(fp))) { 401c216e5adSMichael Roth /* 402c216e5adSMichael Roth * An entry which device name doesn't start with a '/' is 403c216e5adSMichael Roth * either a dummy file system or a network file system. 404c216e5adSMichael Roth * Add special handling for smbfs and cifs as is done by 405c216e5adSMichael Roth * coreutils as well. 406c216e5adSMichael Roth */ 407c216e5adSMichael Roth if ((ment->mnt_fsname[0] != '/') || 408c216e5adSMichael Roth (strcmp(ment->mnt_type, "smbfs") == 0) || 409c216e5adSMichael Roth (strcmp(ment->mnt_type, "cifs") == 0)) { 410c216e5adSMichael Roth continue; 411c216e5adSMichael Roth } 412c216e5adSMichael Roth 413af02203fSPaolo Bonzini mount = g_malloc0(sizeof(FsMount)); 414c216e5adSMichael Roth mount->dirname = g_strdup(ment->mnt_dir); 415c216e5adSMichael Roth mount->devtype = g_strdup(ment->mnt_type); 416c216e5adSMichael Roth 4179e8aded4SMichael Roth QTAILQ_INSERT_TAIL(mounts, mount, next); 418c216e5adSMichael Roth } 419c216e5adSMichael Roth 420c216e5adSMichael Roth endmntent(fp); 421c216e5adSMichael Roth } 422eab5fd59SPaolo Bonzini #endif 423eab5fd59SPaolo Bonzini 424eab5fd59SPaolo Bonzini #if defined(CONFIG_FSFREEZE) 425c216e5adSMichael Roth 426ec0f694cSTomoki Sekiyama typedef enum { 427ec0f694cSTomoki Sekiyama FSFREEZE_HOOK_THAW = 0, 428ec0f694cSTomoki Sekiyama FSFREEZE_HOOK_FREEZE, 429ec0f694cSTomoki Sekiyama } FsfreezeHookArg; 430ec0f694cSTomoki Sekiyama 431ec0f694cSTomoki Sekiyama const char *fsfreeze_hook_arg_string[] = { 432ec0f694cSTomoki Sekiyama "thaw", 433ec0f694cSTomoki Sekiyama "freeze", 434ec0f694cSTomoki Sekiyama }; 435ec0f694cSTomoki Sekiyama 436ec0f694cSTomoki Sekiyama static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) 437ec0f694cSTomoki Sekiyama { 438ec0f694cSTomoki Sekiyama int status; 439ec0f694cSTomoki Sekiyama pid_t pid; 440ec0f694cSTomoki Sekiyama const char *hook; 441ec0f694cSTomoki Sekiyama const char *arg_str = fsfreeze_hook_arg_string[arg]; 442ec0f694cSTomoki Sekiyama Error *local_err = NULL; 443ec0f694cSTomoki Sekiyama 444ec0f694cSTomoki Sekiyama hook = ga_fsfreeze_hook(ga_state); 445ec0f694cSTomoki Sekiyama if (!hook) { 446ec0f694cSTomoki Sekiyama return; 447ec0f694cSTomoki Sekiyama } 448ec0f694cSTomoki Sekiyama if (access(hook, X_OK) != 0) { 449ec0f694cSTomoki Sekiyama error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook); 450ec0f694cSTomoki Sekiyama return; 451ec0f694cSTomoki Sekiyama } 452ec0f694cSTomoki Sekiyama 453ec0f694cSTomoki Sekiyama slog("executing fsfreeze hook with arg '%s'", arg_str); 454ec0f694cSTomoki Sekiyama pid = fork(); 455ec0f694cSTomoki Sekiyama if (pid == 0) { 456ec0f694cSTomoki Sekiyama setsid(); 457ec0f694cSTomoki Sekiyama reopen_fd_to_null(0); 458ec0f694cSTomoki Sekiyama reopen_fd_to_null(1); 459ec0f694cSTomoki Sekiyama reopen_fd_to_null(2); 460ec0f694cSTomoki Sekiyama 461ec0f694cSTomoki Sekiyama execle(hook, hook, arg_str, NULL, environ); 462ec0f694cSTomoki Sekiyama _exit(EXIT_FAILURE); 463ec0f694cSTomoki Sekiyama } else if (pid < 0) { 464ec0f694cSTomoki Sekiyama error_setg_errno(err, errno, "failed to create child process"); 465ec0f694cSTomoki Sekiyama return; 466ec0f694cSTomoki Sekiyama } 467ec0f694cSTomoki Sekiyama 468ec0f694cSTomoki Sekiyama ga_wait_child(pid, &status, &local_err); 469ec0f694cSTomoki Sekiyama if (error_is_set(&local_err)) { 470ec0f694cSTomoki Sekiyama error_propagate(err, local_err); 471ec0f694cSTomoki Sekiyama return; 472ec0f694cSTomoki Sekiyama } 473ec0f694cSTomoki Sekiyama 474ec0f694cSTomoki Sekiyama if (!WIFEXITED(status)) { 475ec0f694cSTomoki Sekiyama error_setg(err, "fsfreeze hook has terminated abnormally"); 476ec0f694cSTomoki Sekiyama return; 477ec0f694cSTomoki Sekiyama } 478ec0f694cSTomoki Sekiyama 479ec0f694cSTomoki Sekiyama status = WEXITSTATUS(status); 480ec0f694cSTomoki Sekiyama if (status) { 481ec0f694cSTomoki Sekiyama error_setg(err, "fsfreeze hook has failed with status %d", status); 482ec0f694cSTomoki Sekiyama return; 483ec0f694cSTomoki Sekiyama } 484ec0f694cSTomoki Sekiyama } 485ec0f694cSTomoki Sekiyama 486c216e5adSMichael Roth /* 487c216e5adSMichael Roth * Return status of freeze/thaw 488c216e5adSMichael Roth */ 489c216e5adSMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 490c216e5adSMichael Roth { 491f22d85e9SMichael Roth if (ga_is_frozen(ga_state)) { 492f22d85e9SMichael Roth return GUEST_FSFREEZE_STATUS_FROZEN; 493f22d85e9SMichael Roth } 494f22d85e9SMichael Roth 495f22d85e9SMichael Roth return GUEST_FSFREEZE_STATUS_THAWED; 496c216e5adSMichael Roth } 497c216e5adSMichael Roth 498c216e5adSMichael Roth /* 499c216e5adSMichael Roth * Walk list of mounted file systems in the guest, and freeze the ones which 500c216e5adSMichael Roth * are real local file systems. 501c216e5adSMichael Roth */ 502c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 503c216e5adSMichael Roth { 504c216e5adSMichael Roth int ret = 0, i = 0; 505af02203fSPaolo Bonzini FsMountList mounts; 506af02203fSPaolo Bonzini struct FsMount *mount; 507261551d1SLuiz Capitulino Error *local_err = NULL; 508c216e5adSMichael Roth int fd; 509c216e5adSMichael Roth 510c216e5adSMichael Roth slog("guest-fsfreeze called"); 511c216e5adSMichael Roth 512ec0f694cSTomoki Sekiyama execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err); 513ec0f694cSTomoki Sekiyama if (error_is_set(&local_err)) { 514ec0f694cSTomoki Sekiyama error_propagate(err, local_err); 515ec0f694cSTomoki Sekiyama return -1; 516ec0f694cSTomoki Sekiyama } 517ec0f694cSTomoki Sekiyama 5189e8aded4SMichael Roth QTAILQ_INIT(&mounts); 519261551d1SLuiz Capitulino build_fs_mount_list(&mounts, &local_err); 520261551d1SLuiz Capitulino if (error_is_set(&local_err)) { 521261551d1SLuiz Capitulino error_propagate(err, local_err); 522261551d1SLuiz Capitulino return -1; 523c216e5adSMichael Roth } 524c216e5adSMichael Roth 525c216e5adSMichael Roth /* cannot risk guest agent blocking itself on a write in this state */ 526f22d85e9SMichael Roth ga_set_frozen(ga_state); 527c216e5adSMichael Roth 5289e8aded4SMichael Roth QTAILQ_FOREACH(mount, &mounts, next) { 529c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 530c216e5adSMichael Roth if (fd == -1) { 531617fbbc1SLuiz Capitulino error_setg_errno(err, errno, "failed to open %s", mount->dirname); 532c216e5adSMichael Roth goto error; 533c216e5adSMichael Roth } 534c216e5adSMichael Roth 535c216e5adSMichael Roth /* we try to cull filesytems we know won't work in advance, but other 536c216e5adSMichael Roth * filesytems may not implement fsfreeze for less obvious reasons. 5379e8aded4SMichael Roth * these will report EOPNOTSUPP. we simply ignore these when tallying 5389e8aded4SMichael Roth * the number of frozen filesystems. 5399e8aded4SMichael Roth * 5409e8aded4SMichael Roth * any other error means a failure to freeze a filesystem we 5419e8aded4SMichael Roth * expect to be freezable, so return an error in those cases 5429e8aded4SMichael Roth * and return system to thawed state. 543c216e5adSMichael Roth */ 544c216e5adSMichael Roth ret = ioctl(fd, FIFREEZE); 5459e8aded4SMichael Roth if (ret == -1) { 5469e8aded4SMichael Roth if (errno != EOPNOTSUPP) { 547617fbbc1SLuiz Capitulino error_setg_errno(err, errno, "failed to freeze %s", 548617fbbc1SLuiz Capitulino mount->dirname); 549c216e5adSMichael Roth close(fd); 550c216e5adSMichael Roth goto error; 551c216e5adSMichael Roth } 5529e8aded4SMichael Roth } else { 553c216e5adSMichael Roth i++; 554c216e5adSMichael Roth } 5559e8aded4SMichael Roth close(fd); 5569e8aded4SMichael Roth } 557c216e5adSMichael Roth 558af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 559c216e5adSMichael Roth return i; 560c216e5adSMichael Roth 561c216e5adSMichael Roth error: 562af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 563c216e5adSMichael Roth qmp_guest_fsfreeze_thaw(NULL); 564c216e5adSMichael Roth return 0; 565c216e5adSMichael Roth } 566c216e5adSMichael Roth 567c216e5adSMichael Roth /* 568c216e5adSMichael Roth * Walk list of frozen file systems in the guest, and thaw them. 569c216e5adSMichael Roth */ 570c216e5adSMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 571c216e5adSMichael Roth { 572c216e5adSMichael Roth int ret; 573af02203fSPaolo Bonzini FsMountList mounts; 574af02203fSPaolo Bonzini FsMount *mount; 5759e8aded4SMichael Roth int fd, i = 0, logged; 576261551d1SLuiz Capitulino Error *local_err = NULL; 577c216e5adSMichael Roth 5789e8aded4SMichael Roth QTAILQ_INIT(&mounts); 579261551d1SLuiz Capitulino build_fs_mount_list(&mounts, &local_err); 580261551d1SLuiz Capitulino if (error_is_set(&local_err)) { 581261551d1SLuiz Capitulino error_propagate(err, local_err); 5829e8aded4SMichael Roth return 0; 5839e8aded4SMichael Roth } 5849e8aded4SMichael Roth 5859e8aded4SMichael Roth QTAILQ_FOREACH(mount, &mounts, next) { 5869e8aded4SMichael Roth logged = false; 587c216e5adSMichael Roth fd = qemu_open(mount->dirname, O_RDONLY); 588c216e5adSMichael Roth if (fd == -1) { 589c216e5adSMichael Roth continue; 590c216e5adSMichael Roth } 5919e8aded4SMichael Roth /* we have no way of knowing whether a filesystem was actually unfrozen 5929e8aded4SMichael Roth * as a result of a successful call to FITHAW, only that if an error 5939e8aded4SMichael Roth * was returned the filesystem was *not* unfrozen by that particular 5949e8aded4SMichael Roth * call. 5959e8aded4SMichael Roth * 596a31f0531SJim Meyering * since multiple preceding FIFREEZEs require multiple calls to FITHAW 5979e8aded4SMichael Roth * to unfreeze, continuing issuing FITHAW until an error is returned, 5989e8aded4SMichael Roth * in which case either the filesystem is in an unfreezable state, or, 5999e8aded4SMichael Roth * more likely, it was thawed previously (and remains so afterward). 6009e8aded4SMichael Roth * 6019e8aded4SMichael Roth * also, since the most recent successful call is the one that did 6029e8aded4SMichael Roth * the actual unfreeze, we can use this to provide an accurate count 6039e8aded4SMichael Roth * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which 6049e8aded4SMichael Roth * may * be useful for determining whether a filesystem was unfrozen 6059e8aded4SMichael Roth * during the freeze/thaw phase by a process other than qemu-ga. 6069e8aded4SMichael Roth */ 6079e8aded4SMichael Roth do { 608c216e5adSMichael Roth ret = ioctl(fd, FITHAW); 6099e8aded4SMichael Roth if (ret == 0 && !logged) { 610c216e5adSMichael Roth i++; 6119e8aded4SMichael Roth logged = true; 6129e8aded4SMichael Roth } 6139e8aded4SMichael Roth } while (ret == 0); 6149e8aded4SMichael Roth close(fd); 615c216e5adSMichael Roth } 616c216e5adSMichael Roth 617f22d85e9SMichael Roth ga_unset_frozen(ga_state); 618af02203fSPaolo Bonzini free_fs_mount_list(&mounts); 619ec0f694cSTomoki Sekiyama 620ec0f694cSTomoki Sekiyama execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err); 621ec0f694cSTomoki Sekiyama 622c216e5adSMichael Roth return i; 623c216e5adSMichael Roth } 624c216e5adSMichael Roth 625c216e5adSMichael Roth static void guest_fsfreeze_cleanup(void) 626c216e5adSMichael Roth { 627c216e5adSMichael Roth Error *err = NULL; 628c216e5adSMichael Roth 629f22d85e9SMichael Roth if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { 6306f686749SMarkus Armbruster qmp_guest_fsfreeze_thaw(&err); 6316f686749SMarkus Armbruster if (err) { 6326f686749SMarkus Armbruster slog("failed to clean up frozen filesystems: %s", 6336f686749SMarkus Armbruster error_get_pretty(err)); 6346f686749SMarkus Armbruster error_free(err); 635c216e5adSMichael Roth } 636c216e5adSMichael Roth } 637c216e5adSMichael Roth } 638e72c3f2eSMichael Roth #endif /* CONFIG_FSFREEZE */ 639c216e5adSMichael Roth 640eab5fd59SPaolo Bonzini #if defined(CONFIG_FSTRIM) 641eab5fd59SPaolo Bonzini /* 642eab5fd59SPaolo Bonzini * Walk list of mounted file systems in the guest, and trim them. 643eab5fd59SPaolo Bonzini */ 644eab5fd59SPaolo Bonzini void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) 645eab5fd59SPaolo Bonzini { 646eab5fd59SPaolo Bonzini int ret = 0; 647eab5fd59SPaolo Bonzini FsMountList mounts; 648eab5fd59SPaolo Bonzini struct FsMount *mount; 649eab5fd59SPaolo Bonzini int fd; 650261551d1SLuiz Capitulino Error *local_err = NULL; 651eab5fd59SPaolo Bonzini struct fstrim_range r = { 652eab5fd59SPaolo Bonzini .start = 0, 653eab5fd59SPaolo Bonzini .len = -1, 654eab5fd59SPaolo Bonzini .minlen = has_minimum ? minimum : 0, 655eab5fd59SPaolo Bonzini }; 656eab5fd59SPaolo Bonzini 657eab5fd59SPaolo Bonzini slog("guest-fstrim called"); 658eab5fd59SPaolo Bonzini 659eab5fd59SPaolo Bonzini QTAILQ_INIT(&mounts); 660261551d1SLuiz Capitulino build_fs_mount_list(&mounts, &local_err); 661261551d1SLuiz Capitulino if (error_is_set(&local_err)) { 662261551d1SLuiz Capitulino error_propagate(err, local_err); 663eab5fd59SPaolo Bonzini return; 664eab5fd59SPaolo Bonzini } 665eab5fd59SPaolo Bonzini 666eab5fd59SPaolo Bonzini QTAILQ_FOREACH(mount, &mounts, next) { 667eab5fd59SPaolo Bonzini fd = qemu_open(mount->dirname, O_RDONLY); 668eab5fd59SPaolo Bonzini if (fd == -1) { 669071673b0SLuiz Capitulino error_setg_errno(err, errno, "failed to open %s", mount->dirname); 670eab5fd59SPaolo Bonzini goto error; 671eab5fd59SPaolo Bonzini } 672eab5fd59SPaolo Bonzini 673eab5fd59SPaolo Bonzini /* We try to cull filesytems we know won't work in advance, but other 674eab5fd59SPaolo Bonzini * filesytems may not implement fstrim for less obvious reasons. These 675eab5fd59SPaolo Bonzini * will report EOPNOTSUPP; we simply ignore these errors. Any other 676eab5fd59SPaolo Bonzini * error means an unexpected error, so return it in those cases. In 677eab5fd59SPaolo Bonzini * some other cases ENOTTY will be reported (e.g. CD-ROMs). 678eab5fd59SPaolo Bonzini */ 679eab5fd59SPaolo Bonzini ret = ioctl(fd, FITRIM, &r); 680eab5fd59SPaolo Bonzini if (ret == -1) { 681eab5fd59SPaolo Bonzini if (errno != ENOTTY && errno != EOPNOTSUPP) { 682071673b0SLuiz Capitulino error_setg_errno(err, errno, "failed to trim %s", 683071673b0SLuiz Capitulino mount->dirname); 684eab5fd59SPaolo Bonzini close(fd); 685eab5fd59SPaolo Bonzini goto error; 686eab5fd59SPaolo Bonzini } 687eab5fd59SPaolo Bonzini } 688eab5fd59SPaolo Bonzini close(fd); 689eab5fd59SPaolo Bonzini } 690eab5fd59SPaolo Bonzini 691eab5fd59SPaolo Bonzini error: 692eab5fd59SPaolo Bonzini free_fs_mount_list(&mounts); 693eab5fd59SPaolo Bonzini } 694eab5fd59SPaolo Bonzini #endif /* CONFIG_FSTRIM */ 695eab5fd59SPaolo Bonzini 696eab5fd59SPaolo Bonzini 69711d0f125SLuiz Capitulino #define LINUX_SYS_STATE_FILE "/sys/power/state" 69811d0f125SLuiz Capitulino #define SUSPEND_SUPPORTED 0 69911d0f125SLuiz Capitulino #define SUSPEND_NOT_SUPPORTED 1 70011d0f125SLuiz Capitulino 70111d0f125SLuiz Capitulino static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, 70211d0f125SLuiz Capitulino const char *sysfile_str, Error **err) 70311d0f125SLuiz Capitulino { 7046b26e837SLuiz Capitulino Error *local_err = NULL; 70511d0f125SLuiz Capitulino char *pmutils_path; 7066b26e837SLuiz Capitulino pid_t pid; 707dc8764f0SLuiz Capitulino int status; 70811d0f125SLuiz Capitulino 70911d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 71011d0f125SLuiz Capitulino 71111d0f125SLuiz Capitulino pid = fork(); 71211d0f125SLuiz Capitulino if (!pid) { 713dc8764f0SLuiz Capitulino char buf[32]; /* hopefully big enough */ 714dc8764f0SLuiz Capitulino ssize_t ret; 715dc8764f0SLuiz Capitulino int fd; 71611d0f125SLuiz Capitulino 71711d0f125SLuiz Capitulino setsid(); 71811d0f125SLuiz Capitulino reopen_fd_to_null(0); 71911d0f125SLuiz Capitulino reopen_fd_to_null(1); 72011d0f125SLuiz Capitulino reopen_fd_to_null(2); 72111d0f125SLuiz Capitulino 72211d0f125SLuiz Capitulino if (pmutils_path) { 72311d0f125SLuiz Capitulino execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ); 72411d0f125SLuiz Capitulino } 72511d0f125SLuiz Capitulino 72611d0f125SLuiz Capitulino /* 72711d0f125SLuiz Capitulino * If we get here either pm-utils is not installed or execle() has 72811d0f125SLuiz Capitulino * failed. Let's try the manual method if the caller wants it. 72911d0f125SLuiz Capitulino */ 73011d0f125SLuiz Capitulino 73111d0f125SLuiz Capitulino if (!sysfile_str) { 73211d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 73311d0f125SLuiz Capitulino } 73411d0f125SLuiz Capitulino 73511d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); 73611d0f125SLuiz Capitulino if (fd < 0) { 73711d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 73811d0f125SLuiz Capitulino } 73911d0f125SLuiz Capitulino 74011d0f125SLuiz Capitulino ret = read(fd, buf, sizeof(buf)-1); 74111d0f125SLuiz Capitulino if (ret <= 0) { 74211d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 74311d0f125SLuiz Capitulino } 74411d0f125SLuiz Capitulino buf[ret] = '\0'; 74511d0f125SLuiz Capitulino 74611d0f125SLuiz Capitulino if (strstr(buf, sysfile_str)) { 74711d0f125SLuiz Capitulino _exit(SUSPEND_SUPPORTED); 74811d0f125SLuiz Capitulino } 74911d0f125SLuiz Capitulino 75011d0f125SLuiz Capitulino _exit(SUSPEND_NOT_SUPPORTED); 7516b26e837SLuiz Capitulino } else if (pid < 0) { 7526b26e837SLuiz Capitulino error_setg_errno(err, errno, "failed to create child process"); 7536b26e837SLuiz Capitulino goto out; 75411d0f125SLuiz Capitulino } 75511d0f125SLuiz Capitulino 7566b26e837SLuiz Capitulino ga_wait_child(pid, &status, &local_err); 7576b26e837SLuiz Capitulino if (error_is_set(&local_err)) { 7586b26e837SLuiz Capitulino error_propagate(err, local_err); 7596b26e837SLuiz Capitulino goto out; 76011d0f125SLuiz Capitulino } 76111d0f125SLuiz Capitulino 7626b26e837SLuiz Capitulino if (!WIFEXITED(status)) { 7636b26e837SLuiz Capitulino error_setg(err, "child process has terminated abnormally"); 7646b26e837SLuiz Capitulino goto out; 7656b26e837SLuiz Capitulino } 7666b26e837SLuiz Capitulino 767dc8764f0SLuiz Capitulino switch (WEXITSTATUS(status)) { 768dc8764f0SLuiz Capitulino case SUSPEND_SUPPORTED: 7696b26e837SLuiz Capitulino goto out; 770dc8764f0SLuiz Capitulino case SUSPEND_NOT_SUPPORTED: 7716b26e837SLuiz Capitulino error_setg(err, 7726b26e837SLuiz Capitulino "the requested suspend mode is not supported by the guest"); 7736b26e837SLuiz Capitulino goto out; 774dc8764f0SLuiz Capitulino default: 7756b26e837SLuiz Capitulino error_setg(err, 7766b26e837SLuiz Capitulino "the helper program '%s' returned an unexpected exit status" 7776b26e837SLuiz Capitulino " code (%d)", pmutils_path, WEXITSTATUS(status)); 7786b26e837SLuiz Capitulino goto out; 779dc8764f0SLuiz Capitulino } 78011d0f125SLuiz Capitulino 7816b26e837SLuiz Capitulino out: 7826b26e837SLuiz Capitulino g_free(pmutils_path); 78311d0f125SLuiz Capitulino } 78411d0f125SLuiz Capitulino 78511d0f125SLuiz Capitulino static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, 78611d0f125SLuiz Capitulino Error **err) 78711d0f125SLuiz Capitulino { 7887b376087SLuiz Capitulino Error *local_err = NULL; 78911d0f125SLuiz Capitulino char *pmutils_path; 7907b376087SLuiz Capitulino pid_t pid; 791dc8764f0SLuiz Capitulino int status; 79211d0f125SLuiz Capitulino 79311d0f125SLuiz Capitulino pmutils_path = g_find_program_in_path(pmutils_bin); 79411d0f125SLuiz Capitulino 79511d0f125SLuiz Capitulino pid = fork(); 79611d0f125SLuiz Capitulino if (pid == 0) { 79711d0f125SLuiz Capitulino /* child */ 79811d0f125SLuiz Capitulino int fd; 79911d0f125SLuiz Capitulino 80011d0f125SLuiz Capitulino setsid(); 80111d0f125SLuiz Capitulino reopen_fd_to_null(0); 80211d0f125SLuiz Capitulino reopen_fd_to_null(1); 80311d0f125SLuiz Capitulino reopen_fd_to_null(2); 80411d0f125SLuiz Capitulino 80511d0f125SLuiz Capitulino if (pmutils_path) { 80611d0f125SLuiz Capitulino execle(pmutils_path, pmutils_bin, NULL, environ); 80711d0f125SLuiz Capitulino } 80811d0f125SLuiz Capitulino 80911d0f125SLuiz Capitulino /* 81011d0f125SLuiz Capitulino * If we get here either pm-utils is not installed or execle() has 81111d0f125SLuiz Capitulino * failed. Let's try the manual method if the caller wants it. 81211d0f125SLuiz Capitulino */ 81311d0f125SLuiz Capitulino 81411d0f125SLuiz Capitulino if (!sysfile_str) { 81511d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 81611d0f125SLuiz Capitulino } 81711d0f125SLuiz Capitulino 81811d0f125SLuiz Capitulino fd = open(LINUX_SYS_STATE_FILE, O_WRONLY); 81911d0f125SLuiz Capitulino if (fd < 0) { 82011d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 82111d0f125SLuiz Capitulino } 82211d0f125SLuiz Capitulino 82311d0f125SLuiz Capitulino if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) { 82411d0f125SLuiz Capitulino _exit(EXIT_FAILURE); 82511d0f125SLuiz Capitulino } 82611d0f125SLuiz Capitulino 82711d0f125SLuiz Capitulino _exit(EXIT_SUCCESS); 8287b376087SLuiz Capitulino } else if (pid < 0) { 8297b376087SLuiz Capitulino error_setg_errno(err, errno, "failed to create child process"); 8307b376087SLuiz Capitulino goto out; 83111d0f125SLuiz Capitulino } 83211d0f125SLuiz Capitulino 8337b376087SLuiz Capitulino ga_wait_child(pid, &status, &local_err); 8347b376087SLuiz Capitulino if (error_is_set(&local_err)) { 8357b376087SLuiz Capitulino error_propagate(err, local_err); 8367b376087SLuiz Capitulino goto out; 8377b376087SLuiz Capitulino } 8387b376087SLuiz Capitulino 8397b376087SLuiz Capitulino if (!WIFEXITED(status)) { 8407b376087SLuiz Capitulino error_setg(err, "child process has terminated abnormally"); 8417b376087SLuiz Capitulino goto out; 8427b376087SLuiz Capitulino } 8437b376087SLuiz Capitulino 8447b376087SLuiz Capitulino if (WEXITSTATUS(status)) { 8457b376087SLuiz Capitulino error_setg(err, "child process has failed to suspend"); 8467b376087SLuiz Capitulino goto out; 8477b376087SLuiz Capitulino } 8487b376087SLuiz Capitulino 8497b376087SLuiz Capitulino out: 85011d0f125SLuiz Capitulino g_free(pmutils_path); 85111d0f125SLuiz Capitulino } 85211d0f125SLuiz Capitulino 85311d0f125SLuiz Capitulino void qmp_guest_suspend_disk(Error **err) 85411d0f125SLuiz Capitulino { 85511d0f125SLuiz Capitulino bios_supports_mode("pm-is-supported", "--hibernate", "disk", err); 85611d0f125SLuiz Capitulino if (error_is_set(err)) { 85711d0f125SLuiz Capitulino return; 85811d0f125SLuiz Capitulino } 85911d0f125SLuiz Capitulino 86011d0f125SLuiz Capitulino guest_suspend("pm-hibernate", "disk", err); 86111d0f125SLuiz Capitulino } 86211d0f125SLuiz Capitulino 863fbf42210SLuiz Capitulino void qmp_guest_suspend_ram(Error **err) 864fbf42210SLuiz Capitulino { 865fbf42210SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend", "mem", err); 866fbf42210SLuiz Capitulino if (error_is_set(err)) { 867fbf42210SLuiz Capitulino return; 868fbf42210SLuiz Capitulino } 869fbf42210SLuiz Capitulino 870fbf42210SLuiz Capitulino guest_suspend("pm-suspend", "mem", err); 871fbf42210SLuiz Capitulino } 872fbf42210SLuiz Capitulino 87395f4f404SLuiz Capitulino void qmp_guest_suspend_hybrid(Error **err) 87495f4f404SLuiz Capitulino { 87595f4f404SLuiz Capitulino bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err); 87695f4f404SLuiz Capitulino if (error_is_set(err)) { 87795f4f404SLuiz Capitulino return; 87895f4f404SLuiz Capitulino } 87995f4f404SLuiz Capitulino 88095f4f404SLuiz Capitulino guest_suspend("pm-suspend-hybrid", NULL, err); 88195f4f404SLuiz Capitulino } 88295f4f404SLuiz Capitulino 8833424fc9fSMichal Privoznik static GuestNetworkInterfaceList * 8843424fc9fSMichal Privoznik guest_find_interface(GuestNetworkInterfaceList *head, 8853424fc9fSMichal Privoznik const char *name) 8863424fc9fSMichal Privoznik { 8873424fc9fSMichal Privoznik for (; head; head = head->next) { 8883424fc9fSMichal Privoznik if (strcmp(head->value->name, name) == 0) { 8893424fc9fSMichal Privoznik break; 8903424fc9fSMichal Privoznik } 8913424fc9fSMichal Privoznik } 8923424fc9fSMichal Privoznik 8933424fc9fSMichal Privoznik return head; 8943424fc9fSMichal Privoznik } 8953424fc9fSMichal Privoznik 8963424fc9fSMichal Privoznik /* 8973424fc9fSMichal Privoznik * Build information about guest interfaces 8983424fc9fSMichal Privoznik */ 8993424fc9fSMichal Privoznik GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 9003424fc9fSMichal Privoznik { 9013424fc9fSMichal Privoznik GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; 9023424fc9fSMichal Privoznik struct ifaddrs *ifap, *ifa; 9033424fc9fSMichal Privoznik 9043424fc9fSMichal Privoznik if (getifaddrs(&ifap) < 0) { 905878a0ae0SLuiz Capitulino error_setg_errno(errp, errno, "getifaddrs failed"); 9063424fc9fSMichal Privoznik goto error; 9073424fc9fSMichal Privoznik } 9083424fc9fSMichal Privoznik 9093424fc9fSMichal Privoznik for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 9103424fc9fSMichal Privoznik GuestNetworkInterfaceList *info; 9113424fc9fSMichal Privoznik GuestIpAddressList **address_list = NULL, *address_item = NULL; 9123424fc9fSMichal Privoznik char addr4[INET_ADDRSTRLEN]; 9133424fc9fSMichal Privoznik char addr6[INET6_ADDRSTRLEN]; 9143424fc9fSMichal Privoznik int sock; 9153424fc9fSMichal Privoznik struct ifreq ifr; 9163424fc9fSMichal Privoznik unsigned char *mac_addr; 9173424fc9fSMichal Privoznik void *p; 9183424fc9fSMichal Privoznik 9193424fc9fSMichal Privoznik g_debug("Processing %s interface", ifa->ifa_name); 9203424fc9fSMichal Privoznik 9213424fc9fSMichal Privoznik info = guest_find_interface(head, ifa->ifa_name); 9223424fc9fSMichal Privoznik 9233424fc9fSMichal Privoznik if (!info) { 9243424fc9fSMichal Privoznik info = g_malloc0(sizeof(*info)); 9253424fc9fSMichal Privoznik info->value = g_malloc0(sizeof(*info->value)); 9263424fc9fSMichal Privoznik info->value->name = g_strdup(ifa->ifa_name); 9273424fc9fSMichal Privoznik 9283424fc9fSMichal Privoznik if (!cur_item) { 9293424fc9fSMichal Privoznik head = cur_item = info; 9303424fc9fSMichal Privoznik } else { 9313424fc9fSMichal Privoznik cur_item->next = info; 9323424fc9fSMichal Privoznik cur_item = info; 9333424fc9fSMichal Privoznik } 9343424fc9fSMichal Privoznik } 9353424fc9fSMichal Privoznik 9363424fc9fSMichal Privoznik if (!info->value->has_hardware_address && 9373424fc9fSMichal Privoznik ifa->ifa_flags & SIOCGIFHWADDR) { 9383424fc9fSMichal Privoznik /* we haven't obtained HW address yet */ 9393424fc9fSMichal Privoznik sock = socket(PF_INET, SOCK_STREAM, 0); 9403424fc9fSMichal Privoznik if (sock == -1) { 941878a0ae0SLuiz Capitulino error_setg_errno(errp, errno, "failed to create socket"); 9423424fc9fSMichal Privoznik goto error; 9433424fc9fSMichal Privoznik } 9443424fc9fSMichal Privoznik 9453424fc9fSMichal Privoznik memset(&ifr, 0, sizeof(ifr)); 9461ab516edSJim Meyering pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name); 9473424fc9fSMichal Privoznik if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { 948878a0ae0SLuiz Capitulino error_setg_errno(errp, errno, 949878a0ae0SLuiz Capitulino "failed to get MAC address of %s", 950878a0ae0SLuiz Capitulino ifa->ifa_name); 95110a2158fSMarkus Armbruster close(sock); 9523424fc9fSMichal Privoznik goto error; 9533424fc9fSMichal Privoznik } 9543424fc9fSMichal Privoznik 95510a2158fSMarkus Armbruster close(sock); 9563424fc9fSMichal Privoznik mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; 9573424fc9fSMichal Privoznik 958e4ada482SStefan Weil info->value->hardware_address = 959e4ada482SStefan Weil g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x", 9603424fc9fSMichal Privoznik (int) mac_addr[0], (int) mac_addr[1], 9613424fc9fSMichal Privoznik (int) mac_addr[2], (int) mac_addr[3], 962e4ada482SStefan Weil (int) mac_addr[4], (int) mac_addr[5]); 9633424fc9fSMichal Privoznik 9643424fc9fSMichal Privoznik info->value->has_hardware_address = true; 9653424fc9fSMichal Privoznik } 9663424fc9fSMichal Privoznik 9673424fc9fSMichal Privoznik if (ifa->ifa_addr && 9683424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET) { 9693424fc9fSMichal Privoznik /* interface with IPv4 address */ 9703424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; 9713424fc9fSMichal Privoznik if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { 972878a0ae0SLuiz Capitulino error_setg_errno(errp, errno, "inet_ntop failed"); 9733424fc9fSMichal Privoznik goto error; 9743424fc9fSMichal Privoznik } 9753424fc9fSMichal Privoznik 97610a2158fSMarkus Armbruster address_item = g_malloc0(sizeof(*address_item)); 97710a2158fSMarkus Armbruster address_item->value = g_malloc0(sizeof(*address_item->value)); 9783424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr4); 9793424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; 9803424fc9fSMichal Privoznik 9813424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 9823424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 9833424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 9843424fc9fSMichal Privoznik p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; 9853424fc9fSMichal Privoznik address_item->value->prefix = ctpop32(((uint32_t *) p)[0]); 9863424fc9fSMichal Privoznik } 9873424fc9fSMichal Privoznik } else if (ifa->ifa_addr && 9883424fc9fSMichal Privoznik ifa->ifa_addr->sa_family == AF_INET6) { 9893424fc9fSMichal Privoznik /* interface with IPv6 address */ 9903424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 9913424fc9fSMichal Privoznik if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { 992878a0ae0SLuiz Capitulino error_setg_errno(errp, errno, "inet_ntop failed"); 9933424fc9fSMichal Privoznik goto error; 9943424fc9fSMichal Privoznik } 9953424fc9fSMichal Privoznik 99610a2158fSMarkus Armbruster address_item = g_malloc0(sizeof(*address_item)); 99710a2158fSMarkus Armbruster address_item->value = g_malloc0(sizeof(*address_item->value)); 9983424fc9fSMichal Privoznik address_item->value->ip_address = g_strdup(addr6); 9993424fc9fSMichal Privoznik address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; 10003424fc9fSMichal Privoznik 10013424fc9fSMichal Privoznik if (ifa->ifa_netmask) { 10023424fc9fSMichal Privoznik /* Count the number of set bits in netmask. 10033424fc9fSMichal Privoznik * This is safe as '1' and '0' cannot be shuffled in netmask. */ 10043424fc9fSMichal Privoznik p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; 10053424fc9fSMichal Privoznik address_item->value->prefix = 10063424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[0]) + 10073424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[1]) + 10083424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[2]) + 10093424fc9fSMichal Privoznik ctpop32(((uint32_t *) p)[3]); 10103424fc9fSMichal Privoznik } 10113424fc9fSMichal Privoznik } 10123424fc9fSMichal Privoznik 10133424fc9fSMichal Privoznik if (!address_item) { 10143424fc9fSMichal Privoznik continue; 10153424fc9fSMichal Privoznik } 10163424fc9fSMichal Privoznik 10173424fc9fSMichal Privoznik address_list = &info->value->ip_addresses; 10183424fc9fSMichal Privoznik 10193424fc9fSMichal Privoznik while (*address_list && (*address_list)->next) { 10203424fc9fSMichal Privoznik address_list = &(*address_list)->next; 10213424fc9fSMichal Privoznik } 10223424fc9fSMichal Privoznik 10233424fc9fSMichal Privoznik if (!*address_list) { 10243424fc9fSMichal Privoznik *address_list = address_item; 10253424fc9fSMichal Privoznik } else { 10263424fc9fSMichal Privoznik (*address_list)->next = address_item; 10273424fc9fSMichal Privoznik } 10283424fc9fSMichal Privoznik 10293424fc9fSMichal Privoznik info->value->has_ip_addresses = true; 10303424fc9fSMichal Privoznik 10313424fc9fSMichal Privoznik 10323424fc9fSMichal Privoznik } 10333424fc9fSMichal Privoznik 10343424fc9fSMichal Privoznik freeifaddrs(ifap); 10353424fc9fSMichal Privoznik return head; 10363424fc9fSMichal Privoznik 10373424fc9fSMichal Privoznik error: 10383424fc9fSMichal Privoznik freeifaddrs(ifap); 10393424fc9fSMichal Privoznik qapi_free_GuestNetworkInterfaceList(head); 10403424fc9fSMichal Privoznik return NULL; 10413424fc9fSMichal Privoznik } 10423424fc9fSMichal Privoznik 1043e72c3f2eSMichael Roth #else /* defined(__linux__) */ 1044e72c3f2eSMichael Roth 1045e72c3f2eSMichael Roth void qmp_guest_suspend_disk(Error **err) 1046e72c3f2eSMichael Roth { 1047e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 1048e72c3f2eSMichael Roth } 1049e72c3f2eSMichael Roth 1050e72c3f2eSMichael Roth void qmp_guest_suspend_ram(Error **err) 1051e72c3f2eSMichael Roth { 1052e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 1053e72c3f2eSMichael Roth } 1054e72c3f2eSMichael Roth 1055e72c3f2eSMichael Roth void qmp_guest_suspend_hybrid(Error **err) 1056e72c3f2eSMichael Roth { 1057e72c3f2eSMichael Roth error_set(err, QERR_UNSUPPORTED); 1058e72c3f2eSMichael Roth } 1059e72c3f2eSMichael Roth 1060e72c3f2eSMichael Roth GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) 1061e72c3f2eSMichael Roth { 1062e72c3f2eSMichael Roth error_set(errp, QERR_UNSUPPORTED); 1063e72c3f2eSMichael Roth return NULL; 1064e72c3f2eSMichael Roth } 1065e72c3f2eSMichael Roth 1066e72c3f2eSMichael Roth #endif 1067e72c3f2eSMichael Roth 1068d35d4cb5SMichael Roth #if !defined(CONFIG_FSFREEZE) 1069d35d4cb5SMichael Roth 1070d35d4cb5SMichael Roth GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) 1071d35d4cb5SMichael Roth { 1072d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 1073d35d4cb5SMichael Roth 1074d35d4cb5SMichael Roth return 0; 1075d35d4cb5SMichael Roth } 1076d35d4cb5SMichael Roth 1077d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_freeze(Error **err) 1078d35d4cb5SMichael Roth { 1079d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 1080d35d4cb5SMichael Roth 1081d35d4cb5SMichael Roth return 0; 1082d35d4cb5SMichael Roth } 1083d35d4cb5SMichael Roth 1084d35d4cb5SMichael Roth int64_t qmp_guest_fsfreeze_thaw(Error **err) 1085d35d4cb5SMichael Roth { 1086d35d4cb5SMichael Roth error_set(err, QERR_UNSUPPORTED); 1087d35d4cb5SMichael Roth 1088d35d4cb5SMichael Roth return 0; 1089d35d4cb5SMichael Roth } 1090eab5fd59SPaolo Bonzini #endif /* CONFIG_FSFREEZE */ 1091d35d4cb5SMichael Roth 1092eab5fd59SPaolo Bonzini #if !defined(CONFIG_FSTRIM) 1093eab5fd59SPaolo Bonzini void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) 1094eab5fd59SPaolo Bonzini { 1095eab5fd59SPaolo Bonzini error_set(err, QERR_UNSUPPORTED); 1096eab5fd59SPaolo Bonzini } 1097d35d4cb5SMichael Roth #endif 1098d35d4cb5SMichael Roth 1099c216e5adSMichael Roth /* register init/cleanup routines for stateful command groups */ 1100c216e5adSMichael Roth void ga_command_state_init(GAState *s, GACommandState *cs) 1101c216e5adSMichael Roth { 1102c216e5adSMichael Roth #if defined(CONFIG_FSFREEZE) 1103f22d85e9SMichael Roth ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); 1104c216e5adSMichael Roth #endif 1105c216e5adSMichael Roth ga_command_state_add(cs, guest_file_init, NULL); 1106c216e5adSMichael Roth } 1107