Annotation of qemu/savevm.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU System Emulator
        !             3:  *
        !             4:  * Copyright (c) 2003-2008 Fabrice Bellard
        !             5:  *
        !             6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !             7:  * of this software and associated documentation files (the "Software"), to deal
        !             8:  * in the Software without restriction, including without limitation the rights
        !             9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            10:  * copies of the Software, and to permit persons to whom the Software is
        !            11:  * furnished to do so, subject to the following conditions:
        !            12:  *
        !            13:  * The above copyright notice and this permission notice shall be included in
        !            14:  * all copies or substantial portions of the Software.
        !            15:  *
        !            16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
        !            19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            22:  * THE SOFTWARE.
        !            23:  */
        !            24: #include "qemu-common.h"
        !            25: #include "hw/hw.h"
        !            26: #include "net.h"
        !            27: #include "console.h"
        !            28: #include "sysemu.h"
        !            29: #include "qemu-timer.h"
        !            30: #include "qemu-char.h"
        !            31: #include "block.h"
        !            32: #include "audio/audio.h"
        !            33: #include "migration.h"
        !            34: #include "qemu_socket.h"
        !            35: 
        !            36: #include <unistd.h>
        !            37: #include <fcntl.h>
        !            38: #include <signal.h>
        !            39: #include <time.h>
        !            40: #include <errno.h>
        !            41: #include <sys/time.h>
        !            42: #include <zlib.h>
        !            43: 
        !            44: #ifndef _WIN32
        !            45: #include <sys/times.h>
        !            46: #include <sys/wait.h>
        !            47: #include <termios.h>
        !            48: #include <sys/mman.h>
        !            49: #include <sys/ioctl.h>
        !            50: #include <sys/resource.h>
        !            51: #include <sys/socket.h>
        !            52: #include <netinet/in.h>
        !            53: #include <net/if.h>
        !            54: #if defined(__NetBSD__)
        !            55: #include <net/if_tap.h>
        !            56: #endif
        !            57: #ifdef __linux__
        !            58: #include <linux/if_tun.h>
        !            59: #endif
        !            60: #include <arpa/inet.h>
        !            61: #include <dirent.h>
        !            62: #include <netdb.h>
        !            63: #include <sys/select.h>
        !            64: #ifdef _BSD
        !            65: #include <sys/stat.h>
        !            66: #ifdef __FreeBSD__
        !            67: #include <libutil.h>
        !            68: #else
        !            69: #include <util.h>
        !            70: #endif
        !            71: #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
        !            72: #include <freebsd/stdlib.h>
        !            73: #else
        !            74: #ifdef __linux__
        !            75: #include <pty.h>
        !            76: #include <malloc.h>
        !            77: #include <linux/rtc.h>
        !            78: #endif
        !            79: #endif
        !            80: #endif
        !            81: 
        !            82: #ifdef _WIN32
        !            83: #include <malloc.h>
        !            84: #include <sys/timeb.h>
        !            85: #include <mmsystem.h>
        !            86: #define getopt_long_only getopt_long
        !            87: #define memalign(align, size) malloc(size)
        !            88: #endif
        !            89: 
        !            90: /* point to the block driver where the snapshots are managed */
        !            91: static BlockDriverState *bs_snapshots;
        !            92: 
        !            93: #define SELF_ANNOUNCE_ROUNDS 5
        !            94: #define ETH_P_EXPERIMENTAL 0x01F1 /* just a number */
        !            95: //#define ETH_P_EXPERIMENTAL 0x0012 /* make it the size of the packet */
        !            96: #define EXPERIMENTAL_MAGIC 0xf1f23f4f
        !            97: 
        !            98: static int announce_self_create(uint8_t *buf, 
        !            99:                                uint8_t *mac_addr)
        !           100: {
        !           101:     uint32_t magic = EXPERIMENTAL_MAGIC;
        !           102:     uint16_t proto = htons(ETH_P_EXPERIMENTAL);
        !           103: 
        !           104:     /* FIXME: should we send a different packet (arp/rarp/ping)? */
        !           105: 
        !           106:     memset(buf, 0xff, 6);         /* h_dst */
        !           107:     memcpy(buf + 6, mac_addr, 6); /* h_src */
        !           108:     memcpy(buf + 12, &proto, 2);  /* h_proto */
        !           109:     memcpy(buf + 14, &magic, 4);  /* magic */
        !           110: 
        !           111:     return 18; /* len */
        !           112: }
        !           113: 
        !           114: void qemu_announce_self(void)
        !           115: {
        !           116:     int i, j, len;
        !           117:     VLANState *vlan;
        !           118:     VLANClientState *vc;
        !           119:     uint8_t buf[256];
        !           120: 
        !           121:     for (i = 0; i < nb_nics; i++) {
        !           122:         len = announce_self_create(buf, nd_table[i].macaddr);
        !           123:         vlan = nd_table[i].vlan;
        !           124:         for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
        !           125:             for (j=0; j < SELF_ANNOUNCE_ROUNDS; j++)
        !           126:                 vc->fd_read(vc->opaque, buf, len);
        !           127:         }
        !           128:     }
        !           129: }
        !           130: 
        !           131: /***********************************************************/
        !           132: /* savevm/loadvm support */
        !           133: 
        !           134: #define IO_BUF_SIZE 32768
        !           135: 
        !           136: struct QEMUFile {
        !           137:     QEMUFilePutBufferFunc *put_buffer;
        !           138:     QEMUFileGetBufferFunc *get_buffer;
        !           139:     QEMUFileCloseFunc *close;
        !           140:     QEMUFileRateLimit *rate_limit;
        !           141:     void *opaque;
        !           142:     int is_write;
        !           143: 
        !           144:     int64_t buf_offset; /* start of buffer when writing, end of buffer
        !           145:                            when reading */
        !           146:     int buf_index;
        !           147:     int buf_size; /* 0 when writing */
        !           148:     uint8_t buf[IO_BUF_SIZE];
        !           149: 
        !           150:     int has_error;
        !           151: };
        !           152: 
        !           153: typedef struct QEMUFilePopen
        !           154: {
        !           155:     FILE *popen_file;
        !           156:     QEMUFile *file;
        !           157: } QEMUFilePopen;
        !           158: 
        !           159: typedef struct QEMUFileSocket
        !           160: {
        !           161:     int fd;
        !           162:     QEMUFile *file;
        !           163: } QEMUFileSocket;
        !           164: 
        !           165: static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
        !           166: {
        !           167:     QEMUFileSocket *s = opaque;
        !           168:     ssize_t len;
        !           169: 
        !           170:     do {
        !           171:         len = recv(s->fd, buf, size, 0);
        !           172:     } while (len == -1 && socket_error() == EINTR);
        !           173: 
        !           174:     if (len == -1)
        !           175:         len = -socket_error();
        !           176: 
        !           177:     return len;
        !           178: }
        !           179: 
        !           180: static int socket_close(void *opaque)
        !           181: {
        !           182:     QEMUFileSocket *s = opaque;
        !           183:     qemu_free(s);
        !           184:     return 0;
        !           185: }
        !           186: 
        !           187: static int popen_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
        !           188: {
        !           189:     QEMUFilePopen *s = opaque;
        !           190:     return fwrite(buf, 1, size, s->popen_file);
        !           191: }
        !           192: 
        !           193: static int popen_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
        !           194: {
        !           195:     QEMUFilePopen *s = opaque;
        !           196:     return fread(buf, 1, size, s->popen_file);
        !           197: }
        !           198: 
        !           199: static int popen_close(void *opaque)
        !           200: {
        !           201:     QEMUFilePopen *s = opaque;
        !           202:     pclose(s->popen_file);
        !           203:     qemu_free(s);
        !           204:     return 0;
        !           205: }
        !           206: 
        !           207: QEMUFile *qemu_popen(FILE *popen_file, const char *mode)
        !           208: {
        !           209:     QEMUFilePopen *s;
        !           210: 
        !           211:     if (popen_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
        !           212:         fprintf(stderr, "qemu_popen: Argument validity check failed\n");
        !           213:         return NULL;
        !           214:     }
        !           215: 
        !           216:     s = qemu_mallocz(sizeof(QEMUFilePopen));
        !           217: 
        !           218:     s->popen_file = popen_file;
        !           219: 
        !           220:     if(mode[0] == 'r') {
        !           221:         s->file = qemu_fopen_ops(s, NULL, popen_get_buffer, popen_close, NULL);
        !           222:     } else {
        !           223:         s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL);
        !           224:     }
        !           225:     fprintf(stderr, "qemu_popen: returning result of qemu_fopen_ops\n");
        !           226:     return s->file;
        !           227: }
        !           228: 
        !           229: QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
        !           230: {
        !           231:     FILE *popen_file;
        !           232: 
        !           233:     popen_file = popen(command, mode);
        !           234:     if(popen_file == NULL) {
        !           235:         return NULL;
        !           236:     }
        !           237: 
        !           238:     return qemu_popen(popen_file, mode);
        !           239: }
        !           240: 
        !           241: QEMUFile *qemu_fopen_socket(int fd)
        !           242: {
        !           243:     QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
        !           244: 
        !           245:     s->fd = fd;
        !           246:     s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, NULL);
        !           247:     return s->file;
        !           248: }
        !           249: 
        !           250: typedef struct QEMUFileStdio
        !           251: {
        !           252:     FILE *outfile;
        !           253: } QEMUFileStdio;
        !           254: 
        !           255: static int file_put_buffer(void *opaque, const uint8_t *buf,
        !           256:                             int64_t pos, int size)
        !           257: {
        !           258:     QEMUFileStdio *s = opaque;
        !           259:     fseek(s->outfile, pos, SEEK_SET);
        !           260:     fwrite(buf, 1, size, s->outfile);
        !           261:     return size;
        !           262: }
        !           263: 
        !           264: static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
        !           265: {
        !           266:     QEMUFileStdio *s = opaque;
        !           267:     fseek(s->outfile, pos, SEEK_SET);
        !           268:     return fread(buf, 1, size, s->outfile);
        !           269: }
        !           270: 
        !           271: static int file_close(void *opaque)
        !           272: {
        !           273:     QEMUFileStdio *s = opaque;
        !           274:     fclose(s->outfile);
        !           275:     qemu_free(s);
        !           276:     return 0;
        !           277: }
        !           278: 
        !           279: QEMUFile *qemu_fopen(const char *filename, const char *mode)
        !           280: {
        !           281:     QEMUFileStdio *s;
        !           282: 
        !           283:     s = qemu_mallocz(sizeof(QEMUFileStdio));
        !           284: 
        !           285:     s->outfile = fopen(filename, mode);
        !           286:     if (!s->outfile)
        !           287:         goto fail;
        !           288: 
        !           289:     if (!strcmp(mode, "wb"))
        !           290:         return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL);
        !           291:     else if (!strcmp(mode, "rb"))
        !           292:         return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL);
        !           293: 
        !           294: fail:
        !           295:     if (s->outfile)
        !           296:         fclose(s->outfile);
        !           297:     qemu_free(s);
        !           298:     return NULL;
        !           299: }
        !           300: 
        !           301: typedef struct QEMUFileBdrv
        !           302: {
        !           303:     BlockDriverState *bs;
        !           304:     int64_t base_offset;
        !           305: } QEMUFileBdrv;
        !           306: 
        !           307: static int bdrv_put_buffer(void *opaque, const uint8_t *buf,
        !           308:                            int64_t pos, int size)
        !           309: {
        !           310:     QEMUFileBdrv *s = opaque;
        !           311:     bdrv_pwrite(s->bs, s->base_offset + pos, buf, size);
        !           312:     return size;
        !           313: }
        !           314: 
        !           315: static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
        !           316: {
        !           317:     QEMUFileBdrv *s = opaque;
        !           318:     return bdrv_pread(s->bs, s->base_offset + pos, buf, size);
        !           319: }
        !           320: 
        !           321: static int bdrv_fclose(void *opaque)
        !           322: {
        !           323:     QEMUFileBdrv *s = opaque;
        !           324:     qemu_free(s);
        !           325:     return 0;
        !           326: }
        !           327: 
        !           328: static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
        !           329: {
        !           330:     QEMUFileBdrv *s;
        !           331: 
        !           332:     s = qemu_mallocz(sizeof(QEMUFileBdrv));
        !           333: 
        !           334:     s->bs = bs;
        !           335:     s->base_offset = offset;
        !           336: 
        !           337:     if (is_writable)
        !           338:         return qemu_fopen_ops(s, bdrv_put_buffer, NULL, bdrv_fclose, NULL);
        !           339: 
        !           340:     return qemu_fopen_ops(s, NULL, bdrv_get_buffer, bdrv_fclose, NULL);
        !           341: }
        !           342: 
        !           343: QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
        !           344:                          QEMUFileGetBufferFunc *get_buffer,
        !           345:                          QEMUFileCloseFunc *close,
        !           346:                          QEMUFileRateLimit *rate_limit)
        !           347: {
        !           348:     QEMUFile *f;
        !           349: 
        !           350:     f = qemu_mallocz(sizeof(QEMUFile));
        !           351: 
        !           352:     f->opaque = opaque;
        !           353:     f->put_buffer = put_buffer;
        !           354:     f->get_buffer = get_buffer;
        !           355:     f->close = close;
        !           356:     f->rate_limit = rate_limit;
        !           357:     f->is_write = 0;
        !           358: 
        !           359:     return f;
        !           360: }
        !           361: 
        !           362: int qemu_file_has_error(QEMUFile *f)
        !           363: {
        !           364:     return f->has_error;
        !           365: }
        !           366: 
        !           367: void qemu_fflush(QEMUFile *f)
        !           368: {
        !           369:     if (!f->put_buffer)
        !           370:         return;
        !           371: 
        !           372:     if (f->is_write && f->buf_index > 0) {
        !           373:         int len;
        !           374: 
        !           375:         len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
        !           376:         if (len > 0)
        !           377:             f->buf_offset += f->buf_index;
        !           378:         else
        !           379:             f->has_error = 1;
        !           380:         f->buf_index = 0;
        !           381:     }
        !           382: }
        !           383: 
        !           384: static void qemu_fill_buffer(QEMUFile *f)
        !           385: {
        !           386:     int len;
        !           387: 
        !           388:     if (!f->get_buffer)
        !           389:         return;
        !           390: 
        !           391:     if (f->is_write)
        !           392:         abort();
        !           393: 
        !           394:     len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
        !           395:     if (len > 0) {
        !           396:         f->buf_index = 0;
        !           397:         f->buf_size = len;
        !           398:         f->buf_offset += len;
        !           399:     } else if (len != -EAGAIN)
        !           400:         f->has_error = 1;
        !           401: }
        !           402: 
        !           403: int qemu_fclose(QEMUFile *f)
        !           404: {
        !           405:     int ret = 0;
        !           406:     qemu_fflush(f);
        !           407:     if (f->close)
        !           408:         ret = f->close(f->opaque);
        !           409:     qemu_free(f);
        !           410:     return ret;
        !           411: }
        !           412: 
        !           413: void qemu_file_put_notify(QEMUFile *f)
        !           414: {
        !           415:     f->put_buffer(f->opaque, NULL, 0, 0);
        !           416: }
        !           417: 
        !           418: void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
        !           419: {
        !           420:     int l;
        !           421: 
        !           422:     if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
        !           423:         fprintf(stderr,
        !           424:                 "Attempted to write to buffer while read buffer is not empty\n");
        !           425:         abort();
        !           426:     }
        !           427: 
        !           428:     while (!f->has_error && size > 0) {
        !           429:         l = IO_BUF_SIZE - f->buf_index;
        !           430:         if (l > size)
        !           431:             l = size;
        !           432:         memcpy(f->buf + f->buf_index, buf, l);
        !           433:         f->is_write = 1;
        !           434:         f->buf_index += l;
        !           435:         buf += l;
        !           436:         size -= l;
        !           437:         if (f->buf_index >= IO_BUF_SIZE)
        !           438:             qemu_fflush(f);
        !           439:     }
        !           440: }
        !           441: 
        !           442: void qemu_put_byte(QEMUFile *f, int v)
        !           443: {
        !           444:     if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
        !           445:         fprintf(stderr,
        !           446:                 "Attempted to write to buffer while read buffer is not empty\n");
        !           447:         abort();
        !           448:     }
        !           449: 
        !           450:     f->buf[f->buf_index++] = v;
        !           451:     f->is_write = 1;
        !           452:     if (f->buf_index >= IO_BUF_SIZE)
        !           453:         qemu_fflush(f);
        !           454: }
        !           455: 
        !           456: int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
        !           457: {
        !           458:     int size, l;
        !           459: 
        !           460:     if (f->is_write)
        !           461:         abort();
        !           462: 
        !           463:     size = size1;
        !           464:     while (size > 0) {
        !           465:         l = f->buf_size - f->buf_index;
        !           466:         if (l == 0) {
        !           467:             qemu_fill_buffer(f);
        !           468:             l = f->buf_size - f->buf_index;
        !           469:             if (l == 0)
        !           470:                 break;
        !           471:         }
        !           472:         if (l > size)
        !           473:             l = size;
        !           474:         memcpy(buf, f->buf + f->buf_index, l);
        !           475:         f->buf_index += l;
        !           476:         buf += l;
        !           477:         size -= l;
        !           478:     }
        !           479:     return size1 - size;
        !           480: }
        !           481: 
        !           482: int qemu_get_byte(QEMUFile *f)
        !           483: {
        !           484:     if (f->is_write)
        !           485:         abort();
        !           486: 
        !           487:     if (f->buf_index >= f->buf_size) {
        !           488:         qemu_fill_buffer(f);
        !           489:         if (f->buf_index >= f->buf_size)
        !           490:             return 0;
        !           491:     }
        !           492:     return f->buf[f->buf_index++];
        !           493: }
        !           494: 
        !           495: int64_t qemu_ftell(QEMUFile *f)
        !           496: {
        !           497:     return f->buf_offset - f->buf_size + f->buf_index;
        !           498: }
        !           499: 
        !           500: int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
        !           501: {
        !           502:     if (whence == SEEK_SET) {
        !           503:         /* nothing to do */
        !           504:     } else if (whence == SEEK_CUR) {
        !           505:         pos += qemu_ftell(f);
        !           506:     } else {
        !           507:         /* SEEK_END not supported */
        !           508:         return -1;
        !           509:     }
        !           510:     if (f->put_buffer) {
        !           511:         qemu_fflush(f);
        !           512:         f->buf_offset = pos;
        !           513:     } else {
        !           514:         f->buf_offset = pos;
        !           515:         f->buf_index = 0;
        !           516:         f->buf_size = 0;
        !           517:     }
        !           518:     return pos;
        !           519: }
        !           520: 
        !           521: int qemu_file_rate_limit(QEMUFile *f)
        !           522: {
        !           523:     if (f->rate_limit)
        !           524:         return f->rate_limit(f->opaque);
        !           525: 
        !           526:     return 0;
        !           527: }
        !           528: 
        !           529: void qemu_put_be16(QEMUFile *f, unsigned int v)
        !           530: {
        !           531:     qemu_put_byte(f, v >> 8);
        !           532:     qemu_put_byte(f, v);
        !           533: }
        !           534: 
        !           535: void qemu_put_be32(QEMUFile *f, unsigned int v)
        !           536: {
        !           537:     qemu_put_byte(f, v >> 24);
        !           538:     qemu_put_byte(f, v >> 16);
        !           539:     qemu_put_byte(f, v >> 8);
        !           540:     qemu_put_byte(f, v);
        !           541: }
        !           542: 
        !           543: void qemu_put_be64(QEMUFile *f, uint64_t v)
        !           544: {
        !           545:     qemu_put_be32(f, v >> 32);
        !           546:     qemu_put_be32(f, v);
        !           547: }
        !           548: 
        !           549: unsigned int qemu_get_be16(QEMUFile *f)
        !           550: {
        !           551:     unsigned int v;
        !           552:     v = qemu_get_byte(f) << 8;
        !           553:     v |= qemu_get_byte(f);
        !           554:     return v;
        !           555: }
        !           556: 
        !           557: unsigned int qemu_get_be32(QEMUFile *f)
        !           558: {
        !           559:     unsigned int v;
        !           560:     v = qemu_get_byte(f) << 24;
        !           561:     v |= qemu_get_byte(f) << 16;
        !           562:     v |= qemu_get_byte(f) << 8;
        !           563:     v |= qemu_get_byte(f);
        !           564:     return v;
        !           565: }
        !           566: 
        !           567: uint64_t qemu_get_be64(QEMUFile *f)
        !           568: {
        !           569:     uint64_t v;
        !           570:     v = (uint64_t)qemu_get_be32(f) << 32;
        !           571:     v |= qemu_get_be32(f);
        !           572:     return v;
        !           573: }
        !           574: 
        !           575: typedef struct SaveStateEntry {
        !           576:     char idstr[256];
        !           577:     int instance_id;
        !           578:     int version_id;
        !           579:     int section_id;
        !           580:     SaveLiveStateHandler *save_live_state;
        !           581:     SaveStateHandler *save_state;
        !           582:     LoadStateHandler *load_state;
        !           583:     void *opaque;
        !           584:     struct SaveStateEntry *next;
        !           585: } SaveStateEntry;
        !           586: 
        !           587: static SaveStateEntry *first_se;
        !           588: 
        !           589: /* TODO: Individual devices generally have very little idea about the rest
        !           590:    of the system, so instance_id should be removed/replaced.
        !           591:    Meanwhile pass -1 as instance_id if you do not already have a clearly
        !           592:    distinguishing id for all instances of your device class. */
        !           593: int register_savevm_live(const char *idstr,
        !           594:                          int instance_id,
        !           595:                          int version_id,
        !           596:                          SaveLiveStateHandler *save_live_state,
        !           597:                          SaveStateHandler *save_state,
        !           598:                          LoadStateHandler *load_state,
        !           599:                          void *opaque)
        !           600: {
        !           601:     SaveStateEntry *se, **pse;
        !           602:     static int global_section_id;
        !           603: 
        !           604:     se = qemu_malloc(sizeof(SaveStateEntry));
        !           605:     pstrcpy(se->idstr, sizeof(se->idstr), idstr);
        !           606:     se->instance_id = (instance_id == -1) ? 0 : instance_id;
        !           607:     se->version_id = version_id;
        !           608:     se->section_id = global_section_id++;
        !           609:     se->save_live_state = save_live_state;
        !           610:     se->save_state = save_state;
        !           611:     se->load_state = load_state;
        !           612:     se->opaque = opaque;
        !           613:     se->next = NULL;
        !           614: 
        !           615:     /* add at the end of list */
        !           616:     pse = &first_se;
        !           617:     while (*pse != NULL) {
        !           618:         if (instance_id == -1
        !           619:                 && strcmp(se->idstr, (*pse)->idstr) == 0
        !           620:                 && se->instance_id <= (*pse)->instance_id)
        !           621:             se->instance_id = (*pse)->instance_id + 1;
        !           622:         pse = &(*pse)->next;
        !           623:     }
        !           624:     *pse = se;
        !           625:     return 0;
        !           626: }
        !           627: 
        !           628: int register_savevm(const char *idstr,
        !           629:                     int instance_id,
        !           630:                     int version_id,
        !           631:                     SaveStateHandler *save_state,
        !           632:                     LoadStateHandler *load_state,
        !           633:                     void *opaque)
        !           634: {
        !           635:     return register_savevm_live(idstr, instance_id, version_id,
        !           636:                                 NULL, save_state, load_state, opaque);
        !           637: }
        !           638: 
        !           639: #define QEMU_VM_FILE_MAGIC           0x5145564d
        !           640: #define QEMU_VM_FILE_VERSION_COMPAT  0x00000002
        !           641: #define QEMU_VM_FILE_VERSION         0x00000003
        !           642: 
        !           643: #define QEMU_VM_EOF                  0x00
        !           644: #define QEMU_VM_SECTION_START        0x01
        !           645: #define QEMU_VM_SECTION_PART         0x02
        !           646: #define QEMU_VM_SECTION_END          0x03
        !           647: #define QEMU_VM_SECTION_FULL         0x04
        !           648: 
        !           649: int qemu_savevm_state_begin(QEMUFile *f)
        !           650: {
        !           651:     SaveStateEntry *se;
        !           652: 
        !           653:     qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
        !           654:     qemu_put_be32(f, QEMU_VM_FILE_VERSION);
        !           655: 
        !           656:     for (se = first_se; se != NULL; se = se->next) {
        !           657:         int len;
        !           658: 
        !           659:         if (se->save_live_state == NULL)
        !           660:             continue;
        !           661: 
        !           662:         /* Section type */
        !           663:         qemu_put_byte(f, QEMU_VM_SECTION_START);
        !           664:         qemu_put_be32(f, se->section_id);
        !           665: 
        !           666:         /* ID string */
        !           667:         len = strlen(se->idstr);
        !           668:         qemu_put_byte(f, len);
        !           669:         qemu_put_buffer(f, (uint8_t *)se->idstr, len);
        !           670: 
        !           671:         qemu_put_be32(f, se->instance_id);
        !           672:         qemu_put_be32(f, se->version_id);
        !           673: 
        !           674:         se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
        !           675:     }
        !           676: 
        !           677:     if (qemu_file_has_error(f))
        !           678:         return -EIO;
        !           679: 
        !           680:     return 0;
        !           681: }
        !           682: 
        !           683: int qemu_savevm_state_iterate(QEMUFile *f)
        !           684: {
        !           685:     SaveStateEntry *se;
        !           686:     int ret = 1;
        !           687: 
        !           688:     for (se = first_se; se != NULL; se = se->next) {
        !           689:         if (se->save_live_state == NULL)
        !           690:             continue;
        !           691: 
        !           692:         /* Section type */
        !           693:         qemu_put_byte(f, QEMU_VM_SECTION_PART);
        !           694:         qemu_put_be32(f, se->section_id);
        !           695: 
        !           696:         ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
        !           697:     }
        !           698: 
        !           699:     if (ret)
        !           700:         return 1;
        !           701: 
        !           702:     if (qemu_file_has_error(f))
        !           703:         return -EIO;
        !           704: 
        !           705:     return 0;
        !           706: }
        !           707: 
        !           708: int qemu_savevm_state_complete(QEMUFile *f)
        !           709: {
        !           710:     SaveStateEntry *se;
        !           711: 
        !           712:     for (se = first_se; se != NULL; se = se->next) {
        !           713:         if (se->save_live_state == NULL)
        !           714:             continue;
        !           715: 
        !           716:         /* Section type */
        !           717:         qemu_put_byte(f, QEMU_VM_SECTION_END);
        !           718:         qemu_put_be32(f, se->section_id);
        !           719: 
        !           720:         se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
        !           721:     }
        !           722: 
        !           723:     for(se = first_se; se != NULL; se = se->next) {
        !           724:         int len;
        !           725: 
        !           726:        if (se->save_state == NULL)
        !           727:            continue;
        !           728: 
        !           729:         /* Section type */
        !           730:         qemu_put_byte(f, QEMU_VM_SECTION_FULL);
        !           731:         qemu_put_be32(f, se->section_id);
        !           732: 
        !           733:         /* ID string */
        !           734:         len = strlen(se->idstr);
        !           735:         qemu_put_byte(f, len);
        !           736:         qemu_put_buffer(f, (uint8_t *)se->idstr, len);
        !           737: 
        !           738:         qemu_put_be32(f, se->instance_id);
        !           739:         qemu_put_be32(f, se->version_id);
        !           740: 
        !           741:         se->save_state(f, se->opaque);
        !           742:     }
        !           743: 
        !           744:     qemu_put_byte(f, QEMU_VM_EOF);
        !           745: 
        !           746:     if (qemu_file_has_error(f))
        !           747:         return -EIO;
        !           748: 
        !           749:     return 0;
        !           750: }
        !           751: 
        !           752: int qemu_savevm_state(QEMUFile *f)
        !           753: {
        !           754:     int saved_vm_running;
        !           755:     int ret;
        !           756: 
        !           757:     saved_vm_running = vm_running;
        !           758:     vm_stop(0);
        !           759: 
        !           760:     bdrv_flush_all();
        !           761: 
        !           762:     ret = qemu_savevm_state_begin(f);
        !           763:     if (ret < 0)
        !           764:         goto out;
        !           765: 
        !           766:     do {
        !           767:         ret = qemu_savevm_state_iterate(f);
        !           768:         if (ret < 0)
        !           769:             goto out;
        !           770:     } while (ret == 0);
        !           771: 
        !           772:     ret = qemu_savevm_state_complete(f);
        !           773: 
        !           774: out:
        !           775:     if (qemu_file_has_error(f))
        !           776:         ret = -EIO;
        !           777: 
        !           778:     if (!ret && saved_vm_running)
        !           779:         vm_start();
        !           780: 
        !           781:     return ret;
        !           782: }
        !           783: 
        !           784: static SaveStateEntry *find_se(const char *idstr, int instance_id)
        !           785: {
        !           786:     SaveStateEntry *se;
        !           787: 
        !           788:     for(se = first_se; se != NULL; se = se->next) {
        !           789:         if (!strcmp(se->idstr, idstr) &&
        !           790:             instance_id == se->instance_id)
        !           791:             return se;
        !           792:     }
        !           793:     return NULL;
        !           794: }
        !           795: 
        !           796: typedef struct LoadStateEntry {
        !           797:     SaveStateEntry *se;
        !           798:     int section_id;
        !           799:     int version_id;
        !           800:     struct LoadStateEntry *next;
        !           801: } LoadStateEntry;
        !           802: 
        !           803: static int qemu_loadvm_state_v2(QEMUFile *f)
        !           804: {
        !           805:     SaveStateEntry *se;
        !           806:     int len, ret, instance_id, record_len, version_id;
        !           807:     int64_t total_len, end_pos, cur_pos;
        !           808:     char idstr[256];
        !           809: 
        !           810:     total_len = qemu_get_be64(f);
        !           811:     end_pos = total_len + qemu_ftell(f);
        !           812:     for(;;) {
        !           813:         if (qemu_ftell(f) >= end_pos)
        !           814:             break;
        !           815:         len = qemu_get_byte(f);
        !           816:         qemu_get_buffer(f, (uint8_t *)idstr, len);
        !           817:         idstr[len] = '\0';
        !           818:         instance_id = qemu_get_be32(f);
        !           819:         version_id = qemu_get_be32(f);
        !           820:         record_len = qemu_get_be32(f);
        !           821:         cur_pos = qemu_ftell(f);
        !           822:         se = find_se(idstr, instance_id);
        !           823:         if (!se) {
        !           824:             fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
        !           825:                     instance_id, idstr);
        !           826:         } else {
        !           827:             ret = se->load_state(f, se->opaque, version_id);
        !           828:             if (ret < 0) {
        !           829:                 fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
        !           830:                         instance_id, idstr);
        !           831:             }
        !           832:         }
        !           833:         /* always seek to exact end of record */
        !           834:         qemu_fseek(f, cur_pos + record_len, SEEK_SET);
        !           835:     }
        !           836: 
        !           837:     if (qemu_file_has_error(f))
        !           838:         return -EIO;
        !           839: 
        !           840:     return 0;
        !           841: }
        !           842: 
        !           843: int qemu_loadvm_state(QEMUFile *f)
        !           844: {
        !           845:     LoadStateEntry *first_le = NULL;
        !           846:     uint8_t section_type;
        !           847:     unsigned int v;
        !           848:     int ret;
        !           849: 
        !           850:     v = qemu_get_be32(f);
        !           851:     if (v != QEMU_VM_FILE_MAGIC)
        !           852:         return -EINVAL;
        !           853: 
        !           854:     v = qemu_get_be32(f);
        !           855:     if (v == QEMU_VM_FILE_VERSION_COMPAT)
        !           856:         return qemu_loadvm_state_v2(f);
        !           857:     if (v != QEMU_VM_FILE_VERSION)
        !           858:         return -ENOTSUP;
        !           859: 
        !           860:     while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
        !           861:         uint32_t instance_id, version_id, section_id;
        !           862:         LoadStateEntry *le;
        !           863:         SaveStateEntry *se;
        !           864:         char idstr[257];
        !           865:         int len;
        !           866: 
        !           867:         switch (section_type) {
        !           868:         case QEMU_VM_SECTION_START:
        !           869:         case QEMU_VM_SECTION_FULL:
        !           870:             /* Read section start */
        !           871:             section_id = qemu_get_be32(f);
        !           872:             len = qemu_get_byte(f);
        !           873:             qemu_get_buffer(f, (uint8_t *)idstr, len);
        !           874:             idstr[len] = 0;
        !           875:             instance_id = qemu_get_be32(f);
        !           876:             version_id = qemu_get_be32(f);
        !           877: 
        !           878:             /* Find savevm section */
        !           879:             se = find_se(idstr, instance_id);
        !           880:             if (se == NULL) {
        !           881:                 fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
        !           882:                 ret = -EINVAL;
        !           883:                 goto out;
        !           884:             }
        !           885: 
        !           886:             /* Validate version */
        !           887:             if (version_id > se->version_id) {
        !           888:                 fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
        !           889:                         version_id, idstr, se->version_id);
        !           890:                 ret = -EINVAL;
        !           891:                 goto out;
        !           892:             }
        !           893: 
        !           894:             /* Add entry */
        !           895:             le = qemu_mallocz(sizeof(*le));
        !           896: 
        !           897:             le->se = se;
        !           898:             le->section_id = section_id;
        !           899:             le->version_id = version_id;
        !           900:             le->next = first_le;
        !           901:             first_le = le;
        !           902: 
        !           903:             le->se->load_state(f, le->se->opaque, le->version_id);
        !           904:             break;
        !           905:         case QEMU_VM_SECTION_PART:
        !           906:         case QEMU_VM_SECTION_END:
        !           907:             section_id = qemu_get_be32(f);
        !           908: 
        !           909:             for (le = first_le; le && le->section_id != section_id; le = le->next);
        !           910:             if (le == NULL) {
        !           911:                 fprintf(stderr, "Unknown savevm section %d\n", section_id);
        !           912:                 ret = -EINVAL;
        !           913:                 goto out;
        !           914:             }
        !           915: 
        !           916:             le->se->load_state(f, le->se->opaque, le->version_id);
        !           917:             break;
        !           918:         default:
        !           919:             fprintf(stderr, "Unknown savevm section type %d\n", section_type);
        !           920:             ret = -EINVAL;
        !           921:             goto out;
        !           922:         }
        !           923:     }
        !           924: 
        !           925:     ret = 0;
        !           926: 
        !           927: out:
        !           928:     while (first_le) {
        !           929:         LoadStateEntry *le = first_le;
        !           930:         first_le = first_le->next;
        !           931:         qemu_free(le);
        !           932:     }
        !           933: 
        !           934:     if (qemu_file_has_error(f))
        !           935:         ret = -EIO;
        !           936: 
        !           937:     return ret;
        !           938: }
        !           939: 
        !           940: /* device can contain snapshots */
        !           941: static int bdrv_can_snapshot(BlockDriverState *bs)
        !           942: {
        !           943:     return (bs &&
        !           944:             !bdrv_is_removable(bs) &&
        !           945:             !bdrv_is_read_only(bs));
        !           946: }
        !           947: 
        !           948: /* device must be snapshots in order to have a reliable snapshot */
        !           949: static int bdrv_has_snapshot(BlockDriverState *bs)
        !           950: {
        !           951:     return (bs &&
        !           952:             !bdrv_is_removable(bs) &&
        !           953:             !bdrv_is_read_only(bs));
        !           954: }
        !           955: 
        !           956: static BlockDriverState *get_bs_snapshots(void)
        !           957: {
        !           958:     BlockDriverState *bs;
        !           959:     int i;
        !           960: 
        !           961:     if (bs_snapshots)
        !           962:         return bs_snapshots;
        !           963:     for(i = 0; i <= nb_drives; i++) {
        !           964:         bs = drives_table[i].bdrv;
        !           965:         if (bdrv_can_snapshot(bs))
        !           966:             goto ok;
        !           967:     }
        !           968:     return NULL;
        !           969:  ok:
        !           970:     bs_snapshots = bs;
        !           971:     return bs;
        !           972: }
        !           973: 
        !           974: static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
        !           975:                               const char *name)
        !           976: {
        !           977:     QEMUSnapshotInfo *sn_tab, *sn;
        !           978:     int nb_sns, i, ret;
        !           979: 
        !           980:     ret = -ENOENT;
        !           981:     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
        !           982:     if (nb_sns < 0)
        !           983:         return ret;
        !           984:     for(i = 0; i < nb_sns; i++) {
        !           985:         sn = &sn_tab[i];
        !           986:         if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
        !           987:             *sn_info = *sn;
        !           988:             ret = 0;
        !           989:             break;
        !           990:         }
        !           991:     }
        !           992:     qemu_free(sn_tab);
        !           993:     return ret;
        !           994: }
        !           995: 
        !           996: void do_savevm(const char *name)
        !           997: {
        !           998:     BlockDriverState *bs, *bs1;
        !           999:     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
        !          1000:     int must_delete, ret, i;
        !          1001:     BlockDriverInfo bdi1, *bdi = &bdi1;
        !          1002:     QEMUFile *f;
        !          1003:     int saved_vm_running;
        !          1004:     uint32_t vm_state_size;
        !          1005: #ifdef _WIN32
        !          1006:     struct _timeb tb;
        !          1007: #else
        !          1008:     struct timeval tv;
        !          1009: #endif
        !          1010: 
        !          1011:     bs = get_bs_snapshots();
        !          1012:     if (!bs) {
        !          1013:         term_printf("No block device can accept snapshots\n");
        !          1014:         return;
        !          1015:     }
        !          1016: 
        !          1017:     /* ??? Should this occur after vm_stop?  */
        !          1018:     qemu_aio_flush();
        !          1019: 
        !          1020:     saved_vm_running = vm_running;
        !          1021:     vm_stop(0);
        !          1022: 
        !          1023:     must_delete = 0;
        !          1024:     if (name) {
        !          1025:         ret = bdrv_snapshot_find(bs, old_sn, name);
        !          1026:         if (ret >= 0) {
        !          1027:             must_delete = 1;
        !          1028:         }
        !          1029:     }
        !          1030:     memset(sn, 0, sizeof(*sn));
        !          1031:     if (must_delete) {
        !          1032:         pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
        !          1033:         pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
        !          1034:     } else {
        !          1035:         if (name)
        !          1036:             pstrcpy(sn->name, sizeof(sn->name), name);
        !          1037:     }
        !          1038: 
        !          1039:     /* fill auxiliary fields */
        !          1040: #ifdef _WIN32
        !          1041:     _ftime(&tb);
        !          1042:     sn->date_sec = tb.time;
        !          1043:     sn->date_nsec = tb.millitm * 1000000;
        !          1044: #else
        !          1045:     gettimeofday(&tv, NULL);
        !          1046:     sn->date_sec = tv.tv_sec;
        !          1047:     sn->date_nsec = tv.tv_usec * 1000;
        !          1048: #endif
        !          1049:     sn->vm_clock_nsec = qemu_get_clock(vm_clock);
        !          1050: 
        !          1051:     if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
        !          1052:         term_printf("Device %s does not support VM state snapshots\n",
        !          1053:                     bdrv_get_device_name(bs));
        !          1054:         goto the_end;
        !          1055:     }
        !          1056: 
        !          1057:     /* save the VM state */
        !          1058:     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);
        !          1059:     if (!f) {
        !          1060:         term_printf("Could not open VM state file\n");
        !          1061:         goto the_end;
        !          1062:     }
        !          1063:     ret = qemu_savevm_state(f);
        !          1064:     vm_state_size = qemu_ftell(f);
        !          1065:     qemu_fclose(f);
        !          1066:     if (ret < 0) {
        !          1067:         term_printf("Error %d while writing VM\n", ret);
        !          1068:         goto the_end;
        !          1069:     }
        !          1070: 
        !          1071:     /* create the snapshots */
        !          1072: 
        !          1073:     for(i = 0; i < nb_drives; i++) {
        !          1074:         bs1 = drives_table[i].bdrv;
        !          1075:         if (bdrv_has_snapshot(bs1)) {
        !          1076:             if (must_delete) {
        !          1077:                 ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
        !          1078:                 if (ret < 0) {
        !          1079:                     term_printf("Error while deleting snapshot on '%s'\n",
        !          1080:                                 bdrv_get_device_name(bs1));
        !          1081:                 }
        !          1082:             }
        !          1083:             /* Write VM state size only to the image that contains the state */
        !          1084:             sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
        !          1085:             ret = bdrv_snapshot_create(bs1, sn);
        !          1086:             if (ret < 0) {
        !          1087:                 term_printf("Error while creating snapshot on '%s'\n",
        !          1088:                             bdrv_get_device_name(bs1));
        !          1089:             }
        !          1090:         }
        !          1091:     }
        !          1092: 
        !          1093:  the_end:
        !          1094:     if (saved_vm_running)
        !          1095:         vm_start();
        !          1096: }
        !          1097: 
        !          1098: void do_loadvm(const char *name)
        !          1099: {
        !          1100:     BlockDriverState *bs, *bs1;
        !          1101:     BlockDriverInfo bdi1, *bdi = &bdi1;
        !          1102:     QEMUSnapshotInfo sn;
        !          1103:     QEMUFile *f;
        !          1104:     int i, ret;
        !          1105:     int saved_vm_running;
        !          1106: 
        !          1107:     bs = get_bs_snapshots();
        !          1108:     if (!bs) {
        !          1109:         term_printf("No block device supports snapshots\n");
        !          1110:         return;
        !          1111:     }
        !          1112: 
        !          1113:     /* Flush all IO requests so they don't interfere with the new state.  */
        !          1114:     qemu_aio_flush();
        !          1115: 
        !          1116:     saved_vm_running = vm_running;
        !          1117:     vm_stop(0);
        !          1118: 
        !          1119:     for(i = 0; i <= nb_drives; i++) {
        !          1120:         bs1 = drives_table[i].bdrv;
        !          1121:         if (bdrv_has_snapshot(bs1)) {
        !          1122:             ret = bdrv_snapshot_goto(bs1, name);
        !          1123:             if (ret < 0) {
        !          1124:                 if (bs != bs1)
        !          1125:                     term_printf("Warning: ");
        !          1126:                 switch(ret) {
        !          1127:                 case -ENOTSUP:
        !          1128:                     term_printf("Snapshots not supported on device '%s'\n",
        !          1129:                                 bdrv_get_device_name(bs1));
        !          1130:                     break;
        !          1131:                 case -ENOENT:
        !          1132:                     term_printf("Could not find snapshot '%s' on device '%s'\n",
        !          1133:                                 name, bdrv_get_device_name(bs1));
        !          1134:                     break;
        !          1135:                 default:
        !          1136:                     term_printf("Error %d while activating snapshot on '%s'\n",
        !          1137:                                 ret, bdrv_get_device_name(bs1));
        !          1138:                     break;
        !          1139:                 }
        !          1140:                 /* fatal on snapshot block device */
        !          1141:                 if (bs == bs1)
        !          1142:                     goto the_end;
        !          1143:             }
        !          1144:         }
        !          1145:     }
        !          1146: 
        !          1147:     if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
        !          1148:         term_printf("Device %s does not support VM state snapshots\n",
        !          1149:                     bdrv_get_device_name(bs));
        !          1150:         return;
        !          1151:     }
        !          1152: 
        !          1153:     /* Don't even try to load empty VM states */
        !          1154:     ret = bdrv_snapshot_find(bs, &sn, name);
        !          1155:     if ((ret >= 0) && (sn.vm_state_size == 0))
        !          1156:         goto the_end;
        !          1157: 
        !          1158:     /* restore the VM state */
        !          1159:     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
        !          1160:     if (!f) {
        !          1161:         term_printf("Could not open VM state file\n");
        !          1162:         goto the_end;
        !          1163:     }
        !          1164:     ret = qemu_loadvm_state(f);
        !          1165:     qemu_fclose(f);
        !          1166:     if (ret < 0) {
        !          1167:         term_printf("Error %d while loading VM state\n", ret);
        !          1168:     }
        !          1169:  the_end:
        !          1170:     if (saved_vm_running)
        !          1171:         vm_start();
        !          1172: }
        !          1173: 
        !          1174: void do_delvm(const char *name)
        !          1175: {
        !          1176:     BlockDriverState *bs, *bs1;
        !          1177:     int i, ret;
        !          1178: 
        !          1179:     bs = get_bs_snapshots();
        !          1180:     if (!bs) {
        !          1181:         term_printf("No block device supports snapshots\n");
        !          1182:         return;
        !          1183:     }
        !          1184: 
        !          1185:     for(i = 0; i <= nb_drives; i++) {
        !          1186:         bs1 = drives_table[i].bdrv;
        !          1187:         if (bdrv_has_snapshot(bs1)) {
        !          1188:             ret = bdrv_snapshot_delete(bs1, name);
        !          1189:             if (ret < 0) {
        !          1190:                 if (ret == -ENOTSUP)
        !          1191:                     term_printf("Snapshots not supported on device '%s'\n",
        !          1192:                                 bdrv_get_device_name(bs1));
        !          1193:                 else
        !          1194:                     term_printf("Error %d while deleting snapshot on '%s'\n",
        !          1195:                                 ret, bdrv_get_device_name(bs1));
        !          1196:             }
        !          1197:         }
        !          1198:     }
        !          1199: }
        !          1200: 
        !          1201: void do_info_snapshots(void)
        !          1202: {
        !          1203:     BlockDriverState *bs, *bs1;
        !          1204:     QEMUSnapshotInfo *sn_tab, *sn;
        !          1205:     int nb_sns, i;
        !          1206:     char buf[256];
        !          1207: 
        !          1208:     bs = get_bs_snapshots();
        !          1209:     if (!bs) {
        !          1210:         term_printf("No available block device supports snapshots\n");
        !          1211:         return;
        !          1212:     }
        !          1213:     term_printf("Snapshot devices:");
        !          1214:     for(i = 0; i <= nb_drives; i++) {
        !          1215:         bs1 = drives_table[i].bdrv;
        !          1216:         if (bdrv_has_snapshot(bs1)) {
        !          1217:             if (bs == bs1)
        !          1218:                 term_printf(" %s", bdrv_get_device_name(bs1));
        !          1219:         }
        !          1220:     }
        !          1221:     term_printf("\n");
        !          1222: 
        !          1223:     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
        !          1224:     if (nb_sns < 0) {
        !          1225:         term_printf("bdrv_snapshot_list: error %d\n", nb_sns);
        !          1226:         return;
        !          1227:     }
        !          1228:     term_printf("Snapshot list (from %s):\n", bdrv_get_device_name(bs));
        !          1229:     term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
        !          1230:     for(i = 0; i < nb_sns; i++) {
        !          1231:         sn = &sn_tab[i];
        !          1232:         term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
        !          1233:     }
        !          1234:     qemu_free(sn_tab);
        !          1235: }

unix.superglobalmegacorp.com