savevm.c revision 986acc9eba2cf7c9b468c2f84764fa478907ac66
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#include <arpa/inet.h>
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dirent.h>
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netdb.h>
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/select.h>
492c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner#ifdef CONFIG_BSD
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h>
51cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libutil.h>
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <util.h>
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <pty.h>
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h>
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/rtc.h>
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <windows.h>
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h>
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/timeb.h>
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <mmsystem.h>
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define getopt_long_only getopt_long
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define memalign(align, size) malloc(size)
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h"
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/hw.h"
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "net.h"
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "monitor.h"
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sysemu.h"
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-timer.h"
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-char.h"
80cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#include "blockdev.h"
812ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije#include "outputchannel.h"
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "block.h"
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio/audio.h"
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "migration.h"
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_socket.h"
86cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#include "qemu-queue.h"
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_file.h"
88622b8f4c760b8c4479d28430f978bad8bb9ea32cTim Baverstock#include "android/snapshot.h"
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define SELF_ANNOUNCE_ROUNDS 5
92986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
93986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#ifndef ETH_P_RARP
94986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ETH_P_RARP 0x8035
95986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#endif
96986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_HTYPE_ETH 0x0001
97986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_PTYPE_IP 0x0800
98986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner#define ARP_OP_REQUEST_REV 0x3
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1005973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turnerstatic int announce_self_create(uint8_t *buf,
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				uint8_t *mac_addr)
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
103986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    /* Ethernet header. */
104986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    memset(buf, 0xff, 6);         /* destination MAC addr */
105986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
106986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
107986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
108986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    /* RARP header. */
109986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
110986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
111986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    *(buf + 18) = 6; /* hardware addr length (ethernet) */
112986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    *(buf + 19) = 4; /* protocol addr length (IPv4) */
113986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
114986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    memcpy(buf + 22, mac_addr, 6); /* source hw addr */
115986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    memset(buf + 28, 0x00, 4);     /* source protocol addr */
116986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    memcpy(buf + 32, mac_addr, 6); /* target hw addr */
117986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    memset(buf + 38, 0x00, 4);     /* target protocol addr */
118986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
119986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
120986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    memset(buf + 42, 0x00, 18);
121986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
122986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return 60; /* len (FCS will be added by hardware) */
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_announce_self_once(void *opaque)
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, len;
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf[256];
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    static int count = SELF_ANNOUNCE_ROUNDS;
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUTimer *timer = *(QEMUTimer **)opaque;
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < MAX_NICS; i++) {
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!nd_table[i].used)
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = announce_self_create(buf, nd_table[i].macaddr);
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan = nd_table[i].vlan;
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vc->receive(vc, buf, len);
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
143986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (--count) {
144986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        /* delay 50ms, 150ms, 250ms, ... */
145986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        qemu_mod_timer(timer, qemu_get_clock_ms(rt_clock) +
146986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner                       50 + (SELF_ANNOUNCE_ROUNDS - count - 1) * 100);
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    qemu_del_timer(timer);
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    qemu_free_timer(timer);
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_announce_self(void)
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	static QEMUTimer *timer;
1565973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner	timer = qemu_new_timer_ms(rt_clock, qemu_announce_self_once, &timer);
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	qemu_announce_self_once(&timer);
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* savevm/loadvm support */
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IO_BUF_SIZE 32768
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct QEMUFile {
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFilePutBufferFunc *put_buffer;
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileGetBufferFunc *get_buffer;
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileCloseFunc *close;
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileRateLimit *rate_limit;
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileSetRateLimit *set_rate_limit;
171a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner    QEMUFileGetRateLimit *get_rate_limit;
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    void *opaque;
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int is_write;
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int64_t buf_offset; /* start of buffer when writing, end of buffer
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           when reading */
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int buf_index;
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int buf_size; /* 0 when writing */
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf[IO_BUF_SIZE];
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int has_error;
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
184986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnertypedef struct QEMUFileStdio
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
186986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    FILE *stdio_file;
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFile *file;
188986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner} QEMUFileStdio;
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct QEMUFileSocket
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFile *file;
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QEMUFileSocket;
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
196986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileSocket *s = opaque;
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ssize_t len;
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    do {
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = recv(s->fd, (void *)buf, size, 0);
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } while (len == -1 && socket_error() == EINTR);
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len == -1)
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = -socket_error();
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len;
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_socket_close(void *opaque)
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileSocket *s = opaque;
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(s);
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
218986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
220986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    QEMUFileStdio *s = opaque;
221986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return fwrite(buf, 1, size, s->stdio_file);
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
224986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
226986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    QEMUFileStdio *s = opaque;
227986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    FILE *fp = s->stdio_file;
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int bytes;
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    do {
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        clearerr(fp);
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        bytes = fread(buf, 1, size, fp);
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } while ((bytes == 0) && ferror(fp) && (errno == EINTR));
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return bytes;
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
237986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_pclose(void *opaque)
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
239986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    QEMUFileStdio *s = opaque;
240986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    int ret;
241986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    ret = pclose(s->stdio_file);
242986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    qemu_free(s);
243986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return ret;
244986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner}
245986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
246986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic int stdio_fclose(void *opaque)
247986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{
248986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    QEMUFileStdio *s = opaque;
249986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    fclose(s->stdio_file);
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(s);
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
254986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' TurnerQEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
256986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    QEMUFileStdio *s;
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
258986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "qemu_popen: Argument validity check failed\n");
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
263986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    s = qemu_mallocz(sizeof(QEMUFileStdio));
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
265986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    s->stdio_file = stdio_file;
2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if(mode[0] == 'r') {
268986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose,
269986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner				 NULL, NULL, NULL);
2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
271986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose,
272986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner				 NULL, NULL, NULL);
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->file;
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_popen_cmd(const char *command, const char *mode)
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FILE *popen_file;
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    popen_file = popen(command, mode);
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if(popen_file == NULL) {
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_popen(popen_file, mode);
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
289986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint qemu_stdio_fd(QEMUFile *f)
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
291986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    QEMUFileStdio *p;
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
294986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    p = (QEMUFileStdio *)f->opaque;
295986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    fd = fileno(p->stdio_file);
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return fd;
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
300986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' TurnerQEMUFile *qemu_fdopen(int fd, const char *mode)
301986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{
302986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    QEMUFileStdio *s;
303986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
304986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (mode == NULL ||
305986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner	(mode[0] != 'r' && mode[0] != 'w') ||
306986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner	mode[1] != 'b' || mode[2] != 0) {
307986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
308986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        return NULL;
309986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    }
310986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
311986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    s = qemu_mallocz(sizeof(QEMUFileStdio));
312986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    s->stdio_file = fdopen(fd, mode);
313986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (!s->stdio_file)
314986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        goto fail;
315986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
316986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if(mode[0] == 'r') {
317986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose,
318986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner				 NULL, NULL, NULL);
319986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    } else {
320986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose,
321986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner				 NULL, NULL, NULL);
322986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    }
323986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return s->file;
324986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
325986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerfail:
326986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    qemu_free(s);
327986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return NULL;
328986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner}
329986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_socket(int fd)
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = fd;
335986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, file_socket_close,
336986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner			     NULL, NULL, NULL);
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->file;
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_put_buffer(void *opaque, const uint8_t *buf,
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            int64_t pos, int size)
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileStdio *s = opaque;
344986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    fseek(s->stdio_file, pos, SEEK_SET);
345986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return fwrite(buf, 1, size, s->stdio_file);
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileStdio *s = opaque;
351986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    fseek(s->stdio_file, pos, SEEK_SET);
352986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return fread(buf, 1, size, s->stdio_file);
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen(const char *filename, const char *mode)
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFileStdio *s;
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
359986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (mode == NULL ||
360986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner	(mode[0] != 'r' && mode[0] != 'w') ||
361986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner	mode[1] != 'b' || mode[2] != 0) {
362986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
363986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        return NULL;
364986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    }
365986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = qemu_mallocz(sizeof(QEMUFileStdio));
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
368986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    s->stdio_file = fopen(filename, mode);
369986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (!s->stdio_file)
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
371986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
372986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if(mode[0] == 'w') {
373986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose,
374986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner				 NULL, NULL, NULL);
375986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    } else {
376986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose,
377986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner			       NULL, NULL, NULL);
378986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    }
379986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return s->file;
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfail:
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(s);
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_put_buffer(void *opaque, const uint8_t *buf,
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           int64_t pos, int size)
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
388986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    bdrv_save_vmstate(opaque, buf, pos, size);
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return size;
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
394986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return bdrv_load_vmstate(opaque, buf, pos, size);
3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_fclose(void *opaque)
3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
402986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerstatic QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_writable)
405986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
406986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner			      NULL, NULL, NULL);
407986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL);
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerQEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         QEMUFileGetBufferFunc *get_buffer,
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         QEMUFileCloseFunc *close,
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         QEMUFileRateLimit *rate_limit,
414a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner                         QEMUFileSetRateLimit *set_rate_limit,
415a12820ef4aff2e2f6d3db9b704abee2c54d08f40David Turner                         QEMUFileGetRateLimit *get_rate_limit)
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFile *f;
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f = qemu_mallocz(sizeof(QEMUFile));
4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->opaque = opaque;
4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->put_buffer = put_buffer;
4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->get_buffer = get_buffer;
4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->close = close;
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->rate_limit = rate_limit;
4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->set_rate_limit = set_rate_limit;
427986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    f->get_rate_limit = get_rate_limit;
4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->is_write = 0;
4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return f;
4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_has_error(QEMUFile *f)
4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return f->has_error;
4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_set_error(QEMUFile *f)
4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->has_error = 1;
4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_fflush(QEMUFile *f)
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f->put_buffer)
4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->is_write && f->buf_index > 0) {
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int len;
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len > 0)
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            f->buf_offset += f->buf_index;
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else
4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            f->has_error = 1;
4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_index = 0;
4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_fill_buffer(QEMUFile *f)
4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len;
4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f->get_buffer)
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->is_write)
4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        abort();
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len > 0) {
4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_index = 0;
4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_size = len;
4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_offset += len;
4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (len != -EAGAIN)
4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->has_error = 1;
4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_fclose(QEMUFile *f)
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret = 0;
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_fflush(f);
4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->close)
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = f->close(f->opaque);
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(f);
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_file_put_notify(QEMUFile *f)
4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->put_buffer(f->opaque, NULL, 0, 0);
4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int l;
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr,
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                "Attempted to write to buffer while read buffer is not empty\n");
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        abort();
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (!f->has_error && size > 0) {
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        l = IO_BUF_SIZE - f->buf_index;
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (l > size)
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            l = size;
5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(f->buf + f->buf_index, buf, l);
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->is_write = 1;
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_index += l;
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buf += l;
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size -= l;
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (f->buf_index >= IO_BUF_SIZE)
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_fflush(f);
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_byte(QEMUFile *f, int v)
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr,
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                "Attempted to write to buffer while read buffer is not empty\n");
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        abort();
5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->buf[f->buf_index++] = v;
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f->is_write = 1;
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->buf_index >= IO_BUF_SIZE)
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_fflush(f);
5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size, l;
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->is_write)
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        abort();
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = size1;
5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (size > 0) {
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        l = f->buf_size - f->buf_index;
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (l == 0) {
5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_fill_buffer(f);
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            l = f->buf_size - f->buf_index;
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (l == 0)
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (l > size)
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            l = size;
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(buf, f->buf + f->buf_index, l);
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_index += l;
5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buf += l;
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size -= l;
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return size1 - size;
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_get_byte(QEMUFile *f)
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->is_write)
5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        abort();
5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->buf_index >= f->buf_size) {
5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_fill_buffer(f);
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (f->buf_index >= f->buf_size)
5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 0;
5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return f->buf[f->buf_index++];
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_ftell(QEMUFile *f)
5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return f->buf_offset - f->buf_size + f->buf_index;
5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (whence == SEEK_SET) {
5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* nothing to do */
5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (whence == SEEK_CUR) {
5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pos += qemu_ftell(f);
5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* SEEK_END not supported */
5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->put_buffer) {
5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_fflush(f);
5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_offset = pos;
5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_offset = pos;
5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_index = 0;
5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        f->buf_size = 0;
5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return pos;
5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_file_rate_limit(QEMUFile *f)
5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (f->rate_limit)
6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return f->rate_limit(f->opaque);
6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
605986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint64_t qemu_file_get_rate_limit(QEMUFile *f)
606986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner{
607986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (f->get_rate_limit)
608986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner        return f->get_rate_limit(f->opaque);
609986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
610986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    return 0;
611986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner}
612986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner
613986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turnerint64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate)
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
615986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    /* any failed or completed migration keeps its state to allow probing of
616986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner     * migration data, but has no associated file anymore */
617986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    if (f && f->set_rate_limit)
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return f->set_rate_limit(f->opaque, new_rate);
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be16(QEMUFile *f, unsigned int v)
6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, v >> 8);
6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, v);
6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be32(QEMUFile *f, unsigned int v)
6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, v >> 24);
6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, v >> 16);
6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, v >> 8);
6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, v);
6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_put_be64(QEMUFile *f, uint64_t v)
6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, v >> 32);
6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, v);
6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be16(QEMUFile *f)
6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned int v;
6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v = qemu_get_byte(f) << 8;
6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v |= qemu_get_byte(f);
6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return v;
6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerunsigned int qemu_get_be32(QEMUFile *f)
6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned int v;
6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v = qemu_get_byte(f) << 24;
6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v |= qemu_get_byte(f) << 16;
6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v |= qemu_get_byte(f) << 8;
6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v |= qemu_get_byte(f);
6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return v;
6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint64_t qemu_get_be64(QEMUFile *f)
6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint64_t v;
6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v = (uint64_t)qemu_get_be32(f) << 32;
6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v |= qemu_get_be32(f);
6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return v;
6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid  qemu_put_struct(QEMUFile*  f, const QField*  fields, const void*  s)
6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const QField*  qf = fields;
6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6737fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije    /* Iterate over struct fields */
6747fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije    while (qf->type != Q_FIELD_END) {
6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint8_t*  p = (uint8_t*)s + qf->offset;
6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (qf->type) {
6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_BYTE:
6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                qemu_put_byte(f, p[0]);
6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_INT16:
6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                qemu_put_be16(f, ((uint16_t*)p)[0]);
6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_INT32:
6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                qemu_put_be32(f, ((uint32_t*)p)[0]);
6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_INT64:
6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                qemu_put_be64(f, ((uint64_t*)p)[0]);
6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_BUFFER:
6917fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije                if (qf[1].type != Q_FIELD_BUFFER_SIZE ||
6927fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije                    qf[2].type != Q_FIELD_BUFFER_SIZE)
6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                {
6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n",
6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            __FUNCTION__ );
6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    exit(1);
6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                else
6995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                {
7007fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije                    uint32_t  size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset;
7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    qemu_put_buffer(f, p, size);
7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    qf += 2;
7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            default:
7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                exit(1);
7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qf++;
7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint   qemu_get_struct(QEMUFile*  f, const QField*  fields, void*  s)
7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const QField*  qf = fields;
7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7187fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije    /* Iterate over struct fields */
7197fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije    while (qf->type != Q_FIELD_END) {
7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint8_t*  p = (uint8_t*)s + qf->offset;
7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (qf->type) {
7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_BYTE:
7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                p[0] = qemu_get_byte(f);
7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_INT16:
7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ((uint16_t*)p)[0] = qemu_get_be16(f);
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_INT32:
7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ((uint32_t*)p)[0] = qemu_get_be32(f);
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_INT64:
7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ((uint64_t*)p)[0] = qemu_get_be64(f);
7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case Q_FIELD_BUFFER:
7367fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije                if (qf[1].type != Q_FIELD_BUFFER_SIZE ||
7377fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije                        qf[2].type != Q_FIELD_BUFFER_SIZE)
7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                {
7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n",
7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            __FUNCTION__ );
7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    return -1;
7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                else
7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                {
7457fd67eba0b961d94a5d6baa8e3c3de37b729f738Ot ten Thije                    uint32_t  size = ((uint32_t)qf[1].offset << 16) | (uint32_t)qf[2].offset;
7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    int       ret  = qemu_get_buffer(f, p, size);
7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    if (ret != size) {
7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__);
7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        return -1;
7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    }
7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    qf += 2;
7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            default:
7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                exit(1);
7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qf++;
7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
764871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* write a float to file */
765871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijevoid qemu_put_float(QEMUFile *f, float v)
766871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
767871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    uint8_t *bytes = (uint8_t*) &v;
768871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_buffer(f, bytes, sizeof(float));
769871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
770871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
771871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* read a float from file */
772871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijefloat qemu_get_float(QEMUFile *f)
773871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
774871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    uint8_t bytes[sizeof(float)];
775871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_get_buffer(f, bytes, sizeof(float));
776871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
777871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return *((float*) bytes);
778871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
779871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct SaveStateEntry {
7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char idstr[256];
7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int instance_id;
7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int version_id;
7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int section_id;
7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveLiveStateHandler *save_live_state;
7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateHandler *save_state;
7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    LoadStateHandler *load_state;
7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    void *opaque;
7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct SaveStateEntry *next;
7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} SaveStateEntry;
7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *first_se;
7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* TODO: Individual devices generally have very little idea about the rest
7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   of the system, so instance_id should be removed/replaced.
7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   Meanwhile pass -1 as instance_id if you do not already have a clearly
7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   distinguishing id for all instances of your device class. */
7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm_live(const char *idstr,
7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         int instance_id,
8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         int version_id,
8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         SaveLiveStateHandler *save_live_state,
8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         SaveStateHandler *save_state,
8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         LoadStateHandler *load_state,
8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         void *opaque)
8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry *se, **pse;
8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    static int global_section_id;
8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se = qemu_malloc(sizeof(SaveStateEntry));
8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pstrcpy(se->idstr, sizeof(se->idstr), idstr);
8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->instance_id = (instance_id == -1) ? 0 : instance_id;
8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->version_id = version_id;
8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->section_id = global_section_id++;
8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->save_live_state = save_live_state;
8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->save_state = save_state;
8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->load_state = load_state;
8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->opaque = opaque;
8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    se->next = NULL;
8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* add at the end of list */
8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pse = &first_se;
8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*pse != NULL) {
8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (instance_id == -1
8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                && strcmp(se->idstr, (*pse)->idstr) == 0
8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                && se->instance_id <= (*pse)->instance_id)
8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            se->instance_id = (*pse)->instance_id + 1;
8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pse = &(*pse)->next;
8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *pse = se;
8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint register_savevm(const char *idstr,
8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    int instance_id,
8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    int version_id,
8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    SaveStateHandler *save_state,
8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    LoadStateHandler *load_state,
8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    void *opaque)
8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return register_savevm_live(idstr, instance_id, version_id,
8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                NULL, save_state, load_state, opaque);
8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid unregister_savevm(const char *idstr, void *opaque)
8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry **pse;
8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pse = &first_se;
8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*pse != NULL) {
8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) {
8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            SaveStateEntry *next = (*pse)->next;
8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_free(*pse);
8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *pse = next;
8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pse = &(*pse)->next;
8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_MAGIC           0x5145564d
8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION_COMPAT  0x00000002
8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_FILE_VERSION         0x00000003
8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_EOF                  0x00
8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_START        0x01
8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_PART         0x02
8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_END          0x03
8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define QEMU_VM_SECTION_FULL         0x04
8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_begin(QEMUFile *f)
8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry *se;
8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_be32(f, QEMU_VM_FILE_VERSION);
8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (se = first_se; se != NULL; se = se->next) {
8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int len;
8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (se->save_live_state == NULL)
8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* Section type */
8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_byte(f, QEMU_VM_SECTION_START);
8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->section_id);
8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* ID string */
8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = strlen(se->idstr);
8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_byte(f, len);
8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->instance_id);
8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->version_id);
8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qemu_file_has_error(f))
8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -EIO;
9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_iterate(QEMUFile *f)
9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry *se;
9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret = 1;
9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (se = first_se; se != NULL; se = se->next) {
9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (se->save_live_state == NULL)
9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* Section type */
9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_byte(f, QEMU_VM_SECTION_PART);
9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->section_id);
9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret)
9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qemu_file_has_error(f))
9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -EIO;
9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state_complete(QEMUFile *f)
9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry *se;
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (se = first_se; se != NULL; se = se->next) {
9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (se->save_live_state == NULL)
9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* Section type */
9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_byte(f, QEMU_VM_SECTION_END);
9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->section_id);
9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(se = first_se; se != NULL; se = se->next) {
9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int len;
9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9478f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije        if (se->save_state == NULL)
9488f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije            continue;
9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* Section type */
9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_byte(f, QEMU_VM_SECTION_FULL);
9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->section_id);
9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* ID string */
9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = strlen(se->idstr);
9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_byte(f, len);
9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->instance_id);
9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_put_be32(f, se->version_id);
9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        se->save_state(f, se->opaque);
9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_put_byte(f, QEMU_VM_EOF);
9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qemu_file_has_error(f))
9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -EIO;
9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_savevm_state(QEMUFile *f)
9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int saved_vm_running;
9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    saved_vm_running = vm_running;
9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vm_stop(0);
9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bdrv_flush_all();
9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qemu_savevm_state_begin(f);
9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0)
9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto out;
9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    do {
9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = qemu_savevm_state_iterate(f);
9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0)
9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } while (ret == 0);
9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qemu_savevm_state_complete(f);
9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout:
9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qemu_file_has_error(f))
9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = -EIO;
9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ret && saved_vm_running)
10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vm_start();
10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic SaveStateEntry *find_se(const char *idstr, int instance_id)
10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry *se;
10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(se = first_se; se != NULL; se = se->next) {
10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!strcmp(se->idstr, idstr) &&
10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            instance_id == se->instance_id)
10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return se;
10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct LoadStateEntry {
10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry *se;
10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int section_id;
10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int version_id;
10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct LoadStateEntry *next;
10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} LoadStateEntry;
10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int qemu_loadvm_state_v2(QEMUFile *f)
10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SaveStateEntry *se;
10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len, ret, instance_id, record_len, version_id;
10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int64_t total_len, end_pos, cur_pos;
10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char idstr[256];
10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    total_len = qemu_get_be64(f);
10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    end_pos = total_len + qemu_ftell(f);
10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(;;) {
10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (qemu_ftell(f) >= end_pos)
10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = qemu_get_byte(f);
10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_get_buffer(f, (uint8_t *)idstr, len);
10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        idstr[len] = '\0';
10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        instance_id = qemu_get_be32(f);
10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        version_id = qemu_get_be32(f);
10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        record_len = qemu_get_be32(f);
10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cur_pos = qemu_ftell(f);
10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        se = find_se(idstr, instance_id);
10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!se) {
10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    instance_id, idstr);
10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = se->load_state(f, se->opaque, version_id);
10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ret < 0) {
10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        instance_id, idstr);
10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return ret;
10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* always seek to exact end of record */
10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_fseek(f, cur_pos + record_len, SEEK_SET);
10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qemu_file_has_error(f))
10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -EIO;
10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_loadvm_state(QEMUFile *f)
10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    LoadStateEntry *first_le = NULL;
10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t section_type;
10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned int v;
10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v = qemu_get_be32(f);
10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (v != QEMU_VM_FILE_MAGIC)
10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -EINVAL;
10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v = qemu_get_be32(f);
10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (v == QEMU_VM_FILE_VERSION_COMPAT)
10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return qemu_loadvm_state_v2(f);
10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (v != QEMU_VM_FILE_VERSION)
10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOTSUP;
10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint32_t instance_id, version_id, section_id;
10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LoadStateEntry *le;
10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        SaveStateEntry *se;
10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char idstr[257];
10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int len;
10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (section_type) {
10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case QEMU_VM_SECTION_START:
10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case QEMU_VM_SECTION_FULL:
10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Read section start */
10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            section_id = qemu_get_be32(f);
10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len = qemu_get_byte(f);
10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_get_buffer(f, (uint8_t *)idstr, len);
10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            idstr[len] = 0;
10975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            instance_id = qemu_get_be32(f);
10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            version_id = qemu_get_be32(f);
10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Find savevm section */
11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            se = find_se(idstr, instance_id);
11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (se == NULL) {
11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -EINVAL;
11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Validate version */
11095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (version_id > se->version_id) {
11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        version_id, idstr, se->version_id);
11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -EINVAL;
11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
11155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Add entry */
11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            le = qemu_mallocz(sizeof(*le));
11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            le->se = se;
11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            le->section_id = section_id;
11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            le->version_id = version_id;
11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            le->next = first_le;
11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            first_le = le;
11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            le->se->load_state(f, le->se->opaque, le->version_id);
11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case QEMU_VM_SECTION_PART:
11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case QEMU_VM_SECTION_END:
11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            section_id = qemu_get_be32(f);
11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (le = first_le; le && le->section_id != section_id; le = le->next);
11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (le == NULL) {
11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "Unknown savevm section %d\n", section_id);
11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -EINVAL;
11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            le->se->load_state(f, le->se->opaque, le->version_id);
11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        default:
11415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "Unknown savevm section type %d\n", section_type);
11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -EINVAL;
11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = 0;
11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout:
11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (first_le) {
11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        LoadStateEntry *le = first_le;
11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        first_le = first_le->next;
11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(le);
11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qemu_file_has_error(f))
11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = -EIO;
11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1161cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#if 0
11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BlockDriverState *get_bs_snapshots(void)
11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriverState *bs;
11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (bs_snapshots)
11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return bs_snapshots;
11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i <= nb_drives; i++) {
11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        bs = drives_table[i].bdrv;
11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (bdrv_can_snapshot(bs))
11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto ok;
11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ok:
11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bs_snapshots = bs;
11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return bs;
11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1179cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#endif
11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              const char *name)
11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUSnapshotInfo *sn_tab, *sn;
11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int nb_sns, i, ret;
11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = -ENOENT;
11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (nb_sns < 0)
11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return ret;
11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < nb_sns; i++) {
11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn = &sn_tab[i];
11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *sn_info = *sn;
11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = 0;
11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(sn_tab);
11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
12005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
12015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12022ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijestatic int
12032ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijemonitor_output_channel_cb(void* opaque, const char* fmt, va_list ap)
12042ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{
12052ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    return monitor_vprintf((Monitor*) opaque, fmt, ap);
12062ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije}
12072ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije
12082ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije
12095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_savevm(Monitor *mon, const char *name)
12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
12112ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
12122ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    do_savevm_oc(oc, name);
12132ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_free(oc);
12142ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije}
12152ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije
12162ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_savevm_oc(OutputChannel *err, const char *name)
12172ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{
12185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriverState *bs, *bs1;
12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
1220cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int must_delete, ret;
12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriverInfo bdi1, *bdi = &bdi1;
12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFile *f;
12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int saved_vm_running;
12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t vm_state_size;
12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct _timeb tb;
12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct timeval tv;
12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1231cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs = bdrv_snapshots();
12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!bs) {
12332ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "No block device can accept snapshots\n");
12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* ??? Should this occur after vm_stop?  */
12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_aio_flush();
12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    saved_vm_running = vm_running;
12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vm_stop(0);
12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    must_delete = 0;
12445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (name) {
12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = bdrv_snapshot_find(bs, old_sn, name);
12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret >= 0) {
12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            must_delete = 1;
12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(sn, 0, sizeof(*sn));
12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (must_delete) {
12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (name)
12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            pstrcpy(sn->name, sizeof(sn->name), name);
12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* fill auxiliary fields */
12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    _ftime(&tb);
12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->date_sec = tb.time;
12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->date_nsec = tb.millitm * 1000000;
12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    gettimeofday(&tv, NULL);
12665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->date_sec = tv.tv_sec;
12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->date_nsec = tv.tv_usec * 1000;
12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
12695973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
12722ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "Device %s does not support VM state snapshots\n",
12732ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                              bdrv_get_device_name(bs));
12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto the_end;
12755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* save the VM state */
1278986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    f = qemu_fopen_bdrv(bs, 1);
12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f) {
12802ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "Could not open VM state file\n");
12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto the_end;
12825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qemu_savevm_state(f);
12845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vm_state_size = qemu_ftell(f);
12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_fclose(f);
12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
12872ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "Error %d while writing VM\n", ret);
12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto the_end;
12895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* create the snapshots */
12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1293cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs1 = NULL;
1294cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    while ((bs1 = bdrv_next(bs1))) {
12958f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije        if (bdrv_can_snapshot(bs1)) {
12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (must_delete) {
12975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
12985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (ret < 0) {
12992ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                    output_channel_printf(err,
13002ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                                          "Error while deleting snapshot on '%s'\n",
13012ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                                          bdrv_get_device_name(bs1));
13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
13035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Write VM state size only to the image that contains the state */
13055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = bdrv_snapshot_create(bs1, sn);
13075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ret < 0) {
13082ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                output_channel_printf(err, "Error while creating snapshot on '%s'\n",
13092ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                                      bdrv_get_device_name(bs1));
13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
13125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end:
13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (saved_vm_running)
13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vm_start();
13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
13185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_loadvm(Monitor *mon, const char *name)
13205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
13212ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
1322622b8f4c760b8c4479d28430f978bad8bb9ea32cTim Baverstock    android_snapshot_update_time_request = 1;
13232ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    do_loadvm_oc(oc, name);
13242ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_free(oc);
13252ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije}
13262ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije
13272ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_loadvm_oc(OutputChannel *err, const char *name)
13282ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{
13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriverState *bs, *bs1;
13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriverInfo bdi1, *bdi = &bdi1;
13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUSnapshotInfo sn;
13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUFile *f;
1333cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int ret;
13345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int saved_vm_running;
13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1336cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs = bdrv_snapshots();
13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!bs) {
13382ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "No block device supports snapshots\n");
13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Flush all IO requests so they don't interfere with the new state.  */
13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_aio_flush();
13445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    saved_vm_running = vm_running;
13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vm_stop(0);
13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1348cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs1 = NULL;
1349cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    while ((bs1 = bdrv_next(bs))) {
13508f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije        if (bdrv_can_snapshot(bs1)) {
13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = bdrv_snapshot_goto(bs1, name);
13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ret < 0) {
13535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (bs != bs1)
13542ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                    output_channel_printf(err, "Warning: ");
13555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                switch(ret) {
13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case -ENOTSUP:
13572ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                    output_channel_printf(err,
13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   "Snapshots not supported on device '%s'\n",
13595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   bdrv_get_device_name(bs1));
13605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    break;
13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case -ENOENT:
13622ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                    output_channel_printf(err, "Could not find snapshot '%s' on "
13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   "device '%s'\n",
13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   name, bdrv_get_device_name(bs1));
13655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    break;
13665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                default:
13672ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                    output_channel_printf(err, "Error %d while activating snapshot on"
13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   " '%s'\n", ret, bdrv_get_device_name(bs1));
13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    break;
13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
13715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                /* fatal on snapshot block device */
13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (bs == bs1)
13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    goto the_end;
13745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
13765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
13792ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "Device %s does not support VM state snapshots\n",
13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                       bdrv_get_device_name(bs));
13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Don't even try to load empty VM states */
13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = bdrv_snapshot_find(bs, &sn, name);
13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((ret >= 0) && (sn.vm_state_size == 0))
13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto the_end;
13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* restore the VM state */
1390986acc9eba2cf7c9b468c2f84764fa478907ac66David 'Digit' Turner    f = qemu_fopen_bdrv(bs, 0);
13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f) {
13922ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "Could not open VM state file\n");
13935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto the_end;
13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qemu_loadvm_state(f);
13965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_fclose(f);
13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
13982ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "Error %d while loading VM state\n", ret);
13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner the_end:
14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (saved_vm_running)
14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vm_start();
14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_delvm(Monitor *mon, const char *name)
14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14072ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
14082ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    do_delvm_oc(oc, name);
14092ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_free(oc);
14102ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije}
14112ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_delvm_oc(OutputChannel *err, const char *name)
14122ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{
14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriverState *bs, *bs1;
1414cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int ret;
14155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1416cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs = bdrv_snapshots();
14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!bs) {
14182ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "No block device supports snapshots\n");
14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1422cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs1 = NULL;
1423cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    while ((bs1 = bdrv_next(bs1))) {
14248f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije        if (bdrv_can_snapshot(bs1)) {
14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = bdrv_snapshot_delete(bs1, name);
14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ret < 0) {
14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (ret == -ENOTSUP)
14282ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                    output_channel_printf(err,
14292ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                                          "Snapshots not supported on device '%s'\n",
14302ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                                          bdrv_get_device_name(bs1));
14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                else
14322ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                    output_channel_printf(err, "Error %d while deleting snapshot on "
14332ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                                          "'%s'\n", ret, bdrv_get_device_name(bs1));
14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
14355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_info_snapshots(Monitor *mon)
14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14412ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
14422ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    do_info_snapshots_oc(oc, oc);
14432ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_free(oc);
14442ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije}
14452ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije
14462ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thijevoid do_info_snapshots_oc(OutputChannel *out, OutputChannel *err)
14472ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije{
14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BlockDriverState *bs, *bs1;
14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUSnapshotInfo *sn_tab, *sn;
14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int nb_sns, i;
14515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[256];
14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1453cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs = bdrv_snapshots();
14545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!bs) {
14552ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "No available block device supports snapshots\n");
14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
14575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14582ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_printf(out, "Snapshot devices:");
1459cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs1 = NULL;
1460cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    while ((bs1 = bdrv_next(bs1))) {
14618f2de6dd4f99bf15ab55b07b88f61c1ba4c65187Ot ten Thije        if (bdrv_can_snapshot(bs1)) {
14625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (bs == bs1)
14632ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije                output_channel_printf(out, " %s", bdrv_get_device_name(bs1));
14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
14655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14662ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_printf(out, "\n");
14675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (nb_sns < 0) {
14702ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(err, "bdrv_snapshot_list: error %d\n", nb_sns);
14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14732ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_printf(out, "Snapshot list (from %s):\n",
14745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                   bdrv_get_device_name(bs));
14752ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije    output_channel_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < nb_sns; i++) {
14775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn = &sn_tab[i];
14782ff39a367738422c0ca1313cac8ff380e1fdd498Ot ten Thije        output_channel_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
14795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(sn_tab);
14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1482