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