savevm.c revision 8f2de6dd4f99bf15ab55b07b88f61c1ba4c65187
15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU System Emulator 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2003-2008 Fabrice Bellard 55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy 75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal 85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in the Software without restriction, including without limitation the rights 95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is 115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * furnished to do so, subject to the following conditions: 125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included in 145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * all copies or substantial portions of the Software. 155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE. 235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <unistd.h> 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <fcntl.h> 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <signal.h> 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <time.h> 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <errno.h> 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/time.h> 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <zlib.h> 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 322c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner/* Needed early for CONFIG_BSD etc. */ 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "config-host.h" 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/times.h> 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/wait.h> 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <termios.h> 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/mman.h> 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/ioctl.h> 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/resource.h> 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/socket.h> 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in.h> 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if.h> 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(__NetBSD__) 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if_tap.h> 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__ 495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/if_tun.h> 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <arpa/inet.h> 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dirent.h> 535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netdb.h> 545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/select.h> 552c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner#ifdef CONFIG_BSD 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h> 575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(__FreeBSD__) || defined(__DragonFly__) 585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libutil.h> 595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <util.h> 615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) 635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <freebsd/stdlib.h> 645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__ 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <pty.h> 675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h> 685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/rtc.h> 695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <windows.h> 755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h> 765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/timeb.h> 775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <mmsystem.h> 785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define getopt_long_only getopt_long 795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define memalign(align, size) malloc(size) 805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h" 835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/hw.h" 845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "net.h" 855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "monitor.h" 865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sysemu.h" 875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-timer.h" 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-char.h" 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "block.h" 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio/audio.h" 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "migration.h" 925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_socket.h" 935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_file.h" 945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* point to the block driver where the snapshots are managed */ 965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriverState *bs_snapshots; 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SELF_ANNOUNCE_ROUNDS 5 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ETH_P_EXPERIMENTAL 0x01F1 /* just a number */ 1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner//#define ETH_P_EXPERIMENTAL 0x0012 /* make it the size of the packet */ 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define EXPERIMENTAL_MAGIC 0xf1f23f4f 1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int announce_self_create(uint8_t *buf, 1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *mac_addr) 1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t magic = EXPERIMENTAL_MAGIC; 1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t proto = htons(ETH_P_EXPERIMENTAL); 1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* FIXME: should we send a different packet (arp/rarp/ping)? */ 1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(buf, 0, 64); 1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(buf, 0xff, 6); /* h_dst */ 1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(buf + 6, mac_addr, 6); /* h_src */ 1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(buf + 12, &proto, 2); /* h_proto */ 1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(buf + 14, &magic, 4); /* magic */ 1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 64; /* len */ 1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_announce_self_once(void *opaque) 1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i, len; 1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner VLANState *vlan; 1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner VLANClientState *vc; 1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t buf[256]; 1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static int count = SELF_ANNOUNCE_ROUNDS; 1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUTimer *timer = *(QEMUTimer **)opaque; 1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < MAX_NICS; i++) { 1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!nd_table[i].used) 1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = announce_self_create(buf, nd_table[i].macaddr); 1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vlan = nd_table[i].vlan; 1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(vc = vlan->first_client; vc != NULL; vc = vc->next) { 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vc->receive(vc, buf, len); 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (count--) { 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_mod_timer(timer, qemu_get_clock(rt_clock) + 100); 1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(timer); 1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_timer(timer); 1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_announce_self(void) 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static QEMUTimer *timer; 1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner timer = qemu_new_timer(rt_clock, qemu_announce_self_once, &timer); 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_announce_self_once(&timer); 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/ 1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* savevm/loadvm support */ 1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IO_BUF_SIZE 32768 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct QEMUFile { 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePutBufferFunc *put_buffer; 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileGetBufferFunc *get_buffer; 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileCloseFunc *close; 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileRateLimit *rate_limit; 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSetRateLimit *set_rate_limit; 164a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileGetRateLimit *get_rate_limit; 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int is_write; 1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t buf_offset; /* start of buffer when writing, end of buffer 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner when reading */ 1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_index; 1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int buf_size; /* 0 when writing */ 1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t buf[IO_BUF_SIZE]; 1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int has_error; 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFilePopen 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FILE *popen_file; 1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFilePopen; 1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFileSocket 1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *file; 1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFileSocket; 1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ssize_t len; 1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = recv(s->fd, (void *)buf, size, 0); 1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (len == -1 && socket_error() == EINTR); 1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len == -1) 1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = -socket_error(); 2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return len; 2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_socket_close(void *opaque) 2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = opaque; 2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int popen_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) 2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePopen *s = opaque; 2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return fwrite(buf, 1, size, s->popen_file); 2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int popen_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePopen *s = opaque; 2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FILE *fp = s->popen_file; 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int bytes; 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner clearerr(fp); 2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bytes = fread(buf, 1, size, fp); 2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while ((bytes == 0) && ferror(fp) && (errno == EINTR)); 2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bytes; 2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int popen_close(void *opaque) 2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePopen *s = opaque; 2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pclose(s->popen_file); 2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_popen(FILE *popen_file, const char *mode) 2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePopen *s; 2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (popen_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { 2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu_popen: Argument validity check failed\n"); 2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFilePopen)); 2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->popen_file = popen_file; 2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(mode[0] == 'r') { 252a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner s->file = qemu_fopen_ops(s, NULL, popen_get_buffer, popen_close, NULL, NULL, NULL); 2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 254a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL, NULL, NULL); 2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->file; 2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_popen_cmd(const char *command, const char *mode) 2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FILE *popen_file; 2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner popen_file = popen(command, mode); 2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if(popen_file == NULL) { 2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return qemu_popen(popen_file, mode); 2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_popen_fd(QEMUFile *f) 2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFilePopen *p; 2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int fd; 2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p = (QEMUFilePopen *)f->opaque; 2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fd = fileno(p->popen_file); 2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return fd; 2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_socket(int fd) 2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket)); 2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->fd = fd; 287a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner s->file = qemu_fopen_ops(s, NULL, file_socket_get_buffer, file_socket_close, NULL, NULL, NULL); 2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->file; 2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFileStdio 2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner FILE *outfile; 2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFileStdio; 2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_put_buffer(void *opaque, const uint8_t *buf, 2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t pos, int size) 2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s = opaque; 3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fseek(s->outfile, pos, SEEK_SET); 3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fwrite(buf, 1, size, s->outfile); 3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size; 3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s = opaque; 3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fseek(s->outfile, pos, SEEK_SET); 3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return fread(buf, 1, size, s->outfile); 3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_close(void *opaque) 3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s = opaque; 3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fclose(s->outfile); 3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen(const char *filename, const char *mode) 3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileStdio *s; 3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileStdio)); 3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->outfile = fopen(filename, mode); 3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!s->outfile) 3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto fail; 3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(mode, "wb")) 331a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL, NULL, NULL); 3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else if (!strcmp(mode, "rb")) 333a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL, NULL, NULL); 3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfail: 3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (s->outfile) 3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fclose(s->outfile); 3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFileBdrv 3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs; 3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t base_offset; 3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFileBdrv; 3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_put_buffer(void *opaque, const uint8_t *buf, 3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t pos, int size) 3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileBdrv *s = opaque; 3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_put_buffer(s->bs, buf, s->base_offset + pos, size); 3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size; 3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) 3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileBdrv *s = opaque; 3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bdrv_get_buffer(s->bs, buf, s->base_offset + pos, size); 3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_fclose(void *opaque) 3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileBdrv *s = opaque; 3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(s); 3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) 3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileBdrv *s; 3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s = qemu_mallocz(sizeof(QEMUFileBdrv)); 3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->bs = bs; 3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->base_offset = offset; 3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (is_writable) 379a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner return qemu_fopen_ops(s, block_put_buffer, NULL, bdrv_fclose, NULL, NULL, NULL); 3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 381a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner return qemu_fopen_ops(s, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL); 3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, 3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileGetBufferFunc *get_buffer, 3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileCloseFunc *close, 3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFileRateLimit *rate_limit, 388a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileSetRateLimit *set_rate_limit, 389a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner QEMUFileGetRateLimit *get_rate_limit) 3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f = qemu_mallocz(sizeof(QEMUFile)); 3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->opaque = opaque; 3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->put_buffer = put_buffer; 3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->get_buffer = get_buffer; 3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->close = close; 3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->rate_limit = rate_limit; 4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->set_rate_limit = set_rate_limit; 4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 0; 4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f; 4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_has_error(QEMUFile *f) 4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->has_error; 4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_set_error(QEMUFile *f) 4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_fflush(QEMUFile *f) 4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->put_buffer) 4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write && f->buf_index > 0) { 4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); 4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 0) 4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset += f->buf_index; 4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_fill_buffer(QEMUFile *f) 4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->get_buffer) 4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE); 4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 0) { 4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_size = len; 4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset += len; 4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (len != -EAGAIN) 4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->has_error = 1; 4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_fclose(QEMUFile *f) 4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 0; 4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->close) 4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = f->close(f->opaque); 4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(f); 4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_put_notify(QEMUFile *f) 4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->put_buffer(f->opaque, NULL, 0, 0); 4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) 4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int l; 4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { 4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, 4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Attempted to write to buffer while read buffer is not empty\n"); 4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (!f->has_error && size > 0) { 4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = IO_BUF_SIZE - f->buf_index; 4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l > size) 4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = size; 4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(f->buf + f->buf_index, buf, l); 4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 1; 4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index += l; 4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner buf += l; 4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size -= l; 4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= IO_BUF_SIZE) 4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_byte(QEMUFile *f, int v) 4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f->has_error && f->is_write == 0 && f->buf_index > 0) { 4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, 4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Attempted to write to buffer while read buffer is not empty\n"); 4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf[f->buf_index++] = v; 5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->is_write = 1; 5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= IO_BUF_SIZE) 5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1) 5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int size, l; 5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size = size1; 5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (size > 0) { 5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = f->buf_size - f->buf_index; 5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l == 0) { 5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fill_buffer(f); 5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = f->buf_size - f->buf_index; 5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l == 0) 5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (l > size) 5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner l = size; 5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(buf, f->buf + f->buf_index, l); 5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index += l; 5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner buf += l; 5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size -= l; 5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return size1 - size; 5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_byte(QEMUFile *f) 5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->is_write) 5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner abort(); 5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= f->buf_size) { 5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fill_buffer(f); 5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->buf_index >= f->buf_size) 5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->buf[f->buf_index++]; 5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_ftell(QEMUFile *f) 5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->buf_offset - f->buf_size + f->buf_index; 5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) 5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (whence == SEEK_SET) { 5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* nothing to do */ 5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (whence == SEEK_CUR) { 5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pos += qemu_ftell(f); 5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* SEEK_END not supported */ 5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->put_buffer) { 5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fflush(f); 5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset = pos; 5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_offset = pos; 5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_index = 0; 5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f->buf_size = 0; 5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return pos; 5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_rate_limit(QEMUFile *f) 5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->rate_limit) 5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->rate_limit(f->opaque); 5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersize_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate) 5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (f->set_rate_limit) 5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return f->set_rate_limit(f->opaque, new_rate); 5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be16(QEMUFile *f, unsigned int v) 5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be32(QEMUFile *f, unsigned int v) 5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 24); 5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 16); 5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v >> 8); 5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, v); 5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be64(QEMUFile *f, uint64_t v) 6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v >> 32); 6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, v); 6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be16(QEMUFile *f) 6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 8; 6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be32(QEMUFile *f) 6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_byte(f) << 24; 6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 16; 6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f) << 8; 6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_byte(f); 6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint64_t qemu_get_be64(QEMUFile *f) 6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint64_t v; 6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = (uint64_t)qemu_get_be32(f) << 32; 6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v |= qemu_get_be32(f); 6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return v; 6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_struct(QEMUFile* f, const QField* fields, const void* s) 6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6367fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 6377fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, p[0]); 6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be16(f, ((uint16_t*)p)[0]); 6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, ((uint32_t*)p)[0]); 6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be64(f, ((uint64_t*)p)[0]); 6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 6547fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 6557fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n", 6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 6637fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, p, size); 6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_struct(QEMUFile* f, const QField* fields, void* s) 6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const QField* qf = fields; 6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6817fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije /* Iterate over struct fields */ 6827fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije while (qf->type != Q_FIELD_END) { 6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t* p = (uint8_t*)s + qf->offset; 6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (qf->type) { 6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BYTE: 6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p[0] = qemu_get_byte(f); 6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT16: 6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint16_t*)p)[0] = qemu_get_be16(f); 6915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT32: 6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint32_t*)p)[0] = qemu_get_be32(f); 6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_INT64: 6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ((uint64_t*)p)[0] = qemu_get_be64(f); 6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case Q_FIELD_BUFFER: 6997fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije if (qf[1].type != Q_FIELD_BUFFER_SIZE || 7007fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije qf[2].type != Q_FIELD_BUFFER_SIZE) 7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n", 7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__ ); 7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner { 7087fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije uint32_t size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset; 7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = qemu_get_buffer(f, p, size); 7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret != size) { 7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__); 7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf += 2; 7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 7195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__); 7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(1); 7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qf++; 7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 727871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* write a float to file */ 728871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijevoid qemu_put_float(QEMUFile *f, float v) 729871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 730871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t *bytes = (uint8_t*) &v; 731871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_put_buffer(f, bytes, sizeof(float)); 732871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 733871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 734871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* read a float from file */ 735871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijefloat qemu_get_float(QEMUFile *f) 736871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{ 737871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije uint8_t bytes[sizeof(float)]; 738871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije qemu_get_buffer(f, bytes, sizeof(float)); 739871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 740871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije return *((float*) bytes); 741871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije} 742871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije 7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct SaveStateEntry { 7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id; 7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state; 7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state; 7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state; 7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct SaveStateEntry *next; 7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} SaveStateEntry; 7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *first_se; 7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* TODO: Individual devices generally have very little idea about the rest 7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner of the system, so instance_id should be removed/replaced. 7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner Meanwhile pass -1 as instance_id if you do not already have a clearly 7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner distinguishing id for all instances of your device class. */ 7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm_live(const char *idstr, 7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveLiveStateHandler *save_live_state, 7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 7665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 7675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se, **pse; 7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner static int global_section_id; 7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = qemu_malloc(sizeof(SaveStateEntry)); 7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(se->idstr, sizeof(se->idstr), idstr); 7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (instance_id == -1) ? 0 : instance_id; 7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->version_id = version_id; 7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->section_id = global_section_id++; 7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state = save_live_state; 7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state = save_state; 7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->load_state = load_state; 7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->opaque = opaque; 7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->next = NULL; 7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* add at the end of list */ 7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (instance_id == -1 7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && strcmp(se->idstr, (*pse)->idstr) == 0 7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner && se->instance_id <= (*pse)->instance_id) 7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->instance_id = (*pse)->instance_id + 1; 7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = se; 7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm(const char *idstr, 7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int instance_id, 7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id, 7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateHandler *save_state, 8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateHandler *load_state, 8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque) 8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return register_savevm_live(idstr, instance_id, version_id, 8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner NULL, save_state, load_state, opaque); 8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid unregister_savevm(const char *idstr, void *opaque) 8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry **pse; 8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &first_se; 8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (*pse != NULL) { 8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) { 8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *next = (*pse)->next; 8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(*pse); 8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *pse = next; 8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pse = &(*pse)->next; 8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_MAGIC 0x5145564d 8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION_COMPAT 0x00000002 8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION 0x00000003 8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_EOF 0x00 8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_START 0x01 8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_PART 0x02 8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_END 0x03 8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_FULL 0x04 8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_begin(QEMUFile *f) 8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_MAGIC); 8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, QEMU_VM_FILE_VERSION); 8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_START); 8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); 8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_iterate(QEMUFile *f) 8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = 1; 8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_PART); 8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); 8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret) 8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 1; 8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_complete(QEMUFile *f) 8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (se = first_se; se != NULL; se = se->next) { 8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se->save_live_state == NULL) 8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner continue; 8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_END); 9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); 9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9108f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (se->save_state == NULL) 9118f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije continue; 9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Section type */ 9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_SECTION_FULL); 9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->section_id); 9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ID string */ 9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = strlen(se->idstr); 9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, len); 9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_buffer(f, (uint8_t *)se->idstr, len); 9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->instance_id); 9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_be32(f, se->version_id); 9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se->save_state(f, se->opaque); 9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_put_byte(f, QEMU_VM_EOF); 9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state(QEMUFile *f) 9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_flush_all(); 9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_begin(f); 9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_iterate(f); 9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) 9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while (ret == 0); 9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state_complete(f); 9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EIO; 9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!ret && saved_vm_running) 9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *find_se(const char *idstr, int instance_id) 9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(se = first_se; se != NULL; se = se->next) { 9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(se->idstr, idstr) && 9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id == se->instance_id) 9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return se; 9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct LoadStateEntry { 9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int section_id; 9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int version_id; 9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct LoadStateEntry *next; 9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} LoadStateEntry; 9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int qemu_loadvm_state_v2(QEMUFile *f) 9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len, ret, instance_id, record_len, version_id; 9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int64_t total_len, end_pos, cur_pos; 9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[256]; 9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner total_len = qemu_get_be64(f); 9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner end_pos = total_len + qemu_ftell(f); 9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(;;) { 9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_ftell(f) >= end_pos) 9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = '\0'; 10025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner record_len = qemu_get_be32(f); 10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cur_pos = qemu_ftell(f); 10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!se) { 10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", 10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = se->load_state(f, se->opaque, version_id); 10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", 10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id, idstr); 10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* always seek to exact end of record */ 10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fseek(f, cur_pos + record_len, SEEK_SET); 10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EIO; 10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_loadvm_state(QEMUFile *f) 10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *first_le = NULL; 10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t section_type; 10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner unsigned int v; 10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret; 10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v != QEMU_VM_FILE_MAGIC) 10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -EINVAL; 10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner v = qemu_get_be32(f); 10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v == QEMU_VM_FILE_VERSION_COMPAT) 10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return qemu_loadvm_state_v2(f); 10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (v != QEMU_VM_FILE_VERSION) 10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENOTSUP; 10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { 10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t instance_id, version_id, section_id; 10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le; 10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner SaveStateEntry *se; 10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char idstr[257]; 10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (section_type) { 10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_START: 10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_FULL: 10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Read section start */ 10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = qemu_get_byte(f); 10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_get_buffer(f, (uint8_t *)idstr, len); 10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner idstr[len] = 0; 10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner instance_id = qemu_get_be32(f); 10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id = qemu_get_be32(f); 10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Find savevm section */ 10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner se = find_se(idstr, instance_id); 10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (se == NULL) { 10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id); 10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Validate version */ 10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (version_id > se->version_id) { 10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n", 10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner version_id, idstr, se->version_id); 10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Add entry */ 10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le = qemu_mallocz(sizeof(*le)); 10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se = se; 10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->section_id = section_id; 10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->version_id = version_id; 10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->next = first_le; 10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = le; 10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se->load_state(f, le->se->opaque, le->version_id); 10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_PART: 10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case QEMU_VM_SECTION_END: 10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner section_id = qemu_get_be32(f); 10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (le = first_le; le && le->section_id != section_id; le = le->next); 10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (le == NULL) { 10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section %d\n", section_id); 10975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner le->se->load_state(f, le->se->opaque, le->version_id); 11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unknown savevm section type %d\n", section_type); 11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EINVAL; 11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (first_le) { 11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LoadStateEntry *le = first_le; 11155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner first_le = first_le->next; 11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(le); 11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (qemu_file_has_error(f)) 11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -EIO; 11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriverState *get_bs_snapshots(void) 11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs; 11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs_snapshots) 11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs_snapshots; 11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i <= nb_drives; i++) { 11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = drives_table[i].bdrv; 11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_can_snapshot(bs)) 11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto ok; 11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ok: 11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs_snapshots = bs; 11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bs; 11415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, 11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const char *name) 11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i, ret; 11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = -ENOENT; 11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) 11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { 11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *sn_info = *sn; 11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = 0; 11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(sn_tab); 11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_savevm(Monitor *mon, const char *name) 11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; 11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int must_delete, ret, i; 11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t vm_state_size; 11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct _timeb tb; 11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct timeval tv; 11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 11795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = get_bs_snapshots(); 11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "No block device can accept snapshots\n"); 11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ??? Should this occur after vm_stop? */ 11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 0; 11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) { 11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, old_sn, name); 11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret >= 0) { 11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner must_delete = 1; 11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(sn, 0, sizeof(*sn)); 12005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 12015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), old_sn->name); 12025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); 12035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 12045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (name) 12055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pstrcpy(sn->name, sizeof(sn->name), name); 12065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fill auxiliary fields */ 12095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32 12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner _ftime(&tb); 12115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tb.time; 12125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tb.millitm * 1000000; 12135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 12145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner gettimeofday(&tv, NULL); 12155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_sec = tv.tv_sec; 12165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->date_nsec = tv.tv_usec * 1000; 12175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 12185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->vm_clock_nsec = qemu_get_clock(vm_clock); 12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Device %s does not support VM state snapshots\n", 12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* save the VM state */ 12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1); 12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Could not open VM state file\n"); 12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 12315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_savevm_state(f); 12335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_state_size = qemu_ftell(f); 12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Error %d while writing VM\n", ret); 12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* create the snapshots */ 12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_drives; i++) { 12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs1 = drives_table[i].bdrv; 12448f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (must_delete) { 12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, old_sn->id_str); 12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, 12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Error while deleting snapshot on '%s'\n", 12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs1)); 12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Write VM state size only to the image that contains the state */ 12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn->vm_state_size = (bs == bs1 ? vm_state_size : 0); 12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_create(bs1, sn); 12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Error while creating snapshot on '%s'\n", 12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs1)); 12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 12665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_loadvm(Monitor *mon, const char *name) 12695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverInfo bdi1, *bdi = &bdi1; 12725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo sn; 12735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUFile *f; 12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i, ret; 12755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int saved_vm_running; 12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = get_bs_snapshots(); 12785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "No block device supports snapshots\n"); 12805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 12825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Flush all IO requests so they don't interfere with the new state. */ 12845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_aio_flush(); 12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner saved_vm_running = vm_running; 12875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_stop(0); 12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i <= nb_drives; i++) { 12905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs1 = drives_table[i].bdrv; 12918f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_goto(bs1, name); 12935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 12945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs != bs1) 12955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Warning: "); 12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch(ret) { 12975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOTSUP: 12985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, 12995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Snapshots not supported on device '%s'\n", 13005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs1)); 13015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case -ENOENT: 13035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Could not find snapshot '%s' on " 13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "device '%s'\n", 13055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner name, bdrv_get_device_name(bs1)); 13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 13085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Error %d while activating snapshot on" 13095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner " '%s'\n", ret, bdrv_get_device_name(bs1)); 13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* fatal on snapshot block device */ 13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { 13205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Device %s does not support VM state snapshots\n", 13215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 13225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 13235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Don't even try to load empty VM states */ 13265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_find(bs, &sn, name); 13275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((ret >= 0) && (sn.vm_state_size == 0)) 13285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* restore the VM state */ 13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0); 13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!f) { 13335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Could not open VM state file\n"); 13345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto the_end; 13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = qemu_loadvm_state(f); 13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_fclose(f); 13385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Error %d while loading VM state\n", ret); 13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end: 13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (saved_vm_running) 13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner vm_start(); 13445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_delvm(Monitor *mon, const char *name) 13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 13495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i, ret; 13505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = get_bs_snapshots(); 13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 13535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "No block device supports snapshots\n"); 13545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 13555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i <= nb_drives; i++) { 13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs1 = drives_table[i].bdrv; 13598f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 13605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = bdrv_snapshot_delete(bs1, name); 13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret < 0) { 13625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (ret == -ENOTSUP) 13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, 13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Snapshots not supported on device '%s'\n", 13655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs1)); 13665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 13675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Error %d while deleting snapshot on " 13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "'%s'\n", ret, bdrv_get_device_name(bs1)); 13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_info_snapshots(Monitor *mon) 13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner BlockDriverState *bs, *bs1; 13775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUSnapshotInfo *sn_tab, *sn; 13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int nb_sns, i; 13795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner char buf[256]; 13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs = get_bs_snapshots(); 13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bs) { 13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "No available block device supports snapshots\n"); 13845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Snapshot devices:"); 13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i <= nb_drives; i++) { 13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bs1 = drives_table[i].bdrv; 13898f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije if (bdrv_can_snapshot(bs1)) { 13905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bs == bs1) 13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, " %s", bdrv_get_device_name(bs1)); 13925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "\n"); 13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner nb_sns = bdrv_snapshot_list(bs, &sn_tab); 13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (nb_sns < 0) { 13985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns); 13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "Snapshot list (from %s):\n", 14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdrv_get_device_name(bs)); 14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); 14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for(i = 0; i < nb_sns; i++) { 14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sn = &sn_tab[i]; 14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); 14075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 14085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(sn_tab); 14095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 1410