snapshot.c revision ef00997efb352a0ab282c9d7bb960be500d3de8b
1ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/*
2ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Copyright (C) 2010 The Android Open Source Project
3ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
4ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Licensed under the Apache License, Version 2.0 (the "License");
5ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * you may not use this file except in compliance with the License.
6ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * You may obtain a copy of the License at
7ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
8ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *      http://www.apache.org/licenses/LICENSE-2.0
9ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
10ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Unless required by applicable law or agreed to in writing, software
11ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * distributed under the License is distributed on an "AS IS" BASIS,
12ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * See the License for the specific language governing permissions and
14ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * limitations under the License.
15ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
16ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
17ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Limited driver for the Qcow2 filesystem, capable of extracting snapshot
18ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * metadata from Qcow2 formatted image file.
19ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
20ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Similar functionality is implemented in block/qcow2.c, block/qcow2-snapshot.c
21ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * and block.c. This separate implementation was made to further decouple the UI
22ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * of the Android emulator from the underlying Qemu system. It allows the UI to
23ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * show snapshot listings without having to fall back on Qemu's block driver
24ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * system, which would pull in a lot of code irrelevant for the UI.
25ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
26ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
27ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <errno.h>
28ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <fcntl.h>
29ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <stdint.h>
30ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <stdio.h>
31ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <stdlib.h>
32ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <string.h>
33ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <time.h>
34ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <unistd.h>
35ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
366e9d1d4fc96a32fbac14d3e489cce32f5c69ade1David 'Digit' Turner#include "qemu/bswap.h"
37ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include "android/utils/debug.h"
38ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include "android/utils/system.h"
39e5af8a259e619973538f393011b1c26a3e2f4afbDavid 'Digit' Turner#include "android/snapshot.h"
40ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
41ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* "Magic" sequence of four bytes required by spec to be the first four bytes
42ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * of any Qcow file.
43ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
44ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
45ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#define QCOW_VERSION 2
46ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
47ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Reads 'nbyte' bytes from 'fd' into 'buf', retrying on interrupts.
48ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Exit()s if the read fails for any other reason.
49ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
50ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic int
51ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijeread_or_die(int fd, void *buf, size_t nbyte)
52ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
53ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int ret = 0;
54ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    do {
55ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        ret = read(fd, buf, nbyte);
56ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
57ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    while(ret < 0 && errno == EINTR);
58ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
59ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (ret < 0) {
60ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("read failed: %s", strerror(errno));
61ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
62ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
63ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
64ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return ret;
65ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
66ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
67ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Wrapper around lseek(), exit()s on error.
68ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
69ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic off_t
70ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijeseek_or_die(int fd, off_t offset, int whence)
71ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
72ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    off_t ret = lseek(fd, offset, whence);
73ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (ret < 0) {
74ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("seek failed: %s", strerror(errno));
75ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
76ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
77ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return ret;
78ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
79ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
80ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
81ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijetypedef struct SnapshotInfo {
82ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char *id_str;
83ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char *name;
84ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
85ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t date_sec;
86ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t date_nsec;
87ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
88ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t vm_clock_nsec;
89ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t vm_state_size;
90ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije} SnapshotInfo;
91ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
92ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic SnapshotInfo*
93ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_alloc()
94ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
95ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return android_alloc(sizeof(SnapshotInfo));
96ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
97ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
98ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
99ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_free( SnapshotInfo* info )
100ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
101ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    AFREE(info->id_str);
102ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    AFREE(info->name);
103ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    AFREE(info);
104ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
105ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
106ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
107ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Reads a snapshot record from a qcow2-formatted file.
108ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
109ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * The function assumes the file position of 'fd' points to the beginning of a
110ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * QcowSnapshotHeader record. When the call returns, the file position of fd is
111ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * at the place where the next QcowSnapshotHeader should start, if there is one.
112ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
113ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * C.f. QCowSnapshotHeader in block/qcow2-snapshot.c for the complete layout of
114ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * the header.
115ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
116ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
117ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_read( int fd, SnapshotInfo* info )
118ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
119ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t start_offset = seek_or_die(fd, 0, SEEK_CUR);
120ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
121ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t extra_data_size;
122ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint16_t id_str_size, name_size;
123ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
124ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read fixed-length fields */
125ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, 12, SEEK_CUR);  /* skip l1 info */
126ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &id_str_size,         sizeof(id_str_size));
127ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &name_size,           sizeof(name_size));
128ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->date_sec,      sizeof(info->date_sec));
129ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->date_nsec,     sizeof(info->date_nsec));
130ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->vm_clock_nsec, sizeof(info->vm_clock_nsec));
131ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->vm_state_size, sizeof(info->vm_state_size));
132ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &extra_data_size,     sizeof(extra_data_size));
133ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
134ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* convert to host endianness */
135ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be16_to_cpus(&id_str_size);
136ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be16_to_cpus(&name_size);
137ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&info->date_sec);
138ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&info->date_nsec);
139ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be64_to_cpus(&info->vm_clock_nsec);
140ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&info->vm_state_size);
141ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&extra_data_size);
142ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&extra_data_size);
143ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
144ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read variable-length buffers*/
145ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->id_str = android_alloc(id_str_size + 1); // +1: manual null-termination
146ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->name   = android_alloc(name_size + 1);
147ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, extra_data_size, SEEK_CUR);  /* skip extra data */
148ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, info->id_str, id_str_size);
149ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, info->name, name_size);
150ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
151ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->id_str[id_str_size] = '\0';
152ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->name[name_size] = '\0';
153ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
154ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* headers are 8 byte aligned, ceil to nearest multiple of 8 */
155ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t end_offset   = seek_or_die(fd, 0, SEEK_CUR);
156ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t total_size   = end_offset - start_offset;
157ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t aligned_size = ((total_size - 1) / 8 + 1) * 8;
158ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
159ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* skip to start of next record */
160ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, start_offset + aligned_size, SEEK_SET);
161ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
162ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
163ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
164ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#define NB_SUFFIXES 4
165ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
166ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Returns the size of a snapshot in a human-readable format.
167ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
168ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * This function copyright (c) 2003 Fabrice Bellard
169ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
170ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic char*
171ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_format_size( char *buf, int buf_size, int64_t size )
172ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
173ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    static const char suffixes[NB_SUFFIXES] = "KMGT";
174ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int64_t base;
175ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int i;
176ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
177ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (size <= 999) {
178ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snprintf(buf, buf_size, "%" PRId64, size);
179ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    } else {
180ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        base = 1024;
181ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        for(i = 0; i < NB_SUFFIXES; i++) {
182ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            if (size < (10 * base)) {
183ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                snprintf(buf, buf_size, "%0.1f%c",
184ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         (double)size / base,
185ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         suffixes[i]);
186ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                break;
187ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
188ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                snprintf(buf, buf_size, "%" PRId64 "%c",
189ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         ((size + (base >> 1)) / base),
190ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         suffixes[i]);
191ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                break;
192ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            }
193ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            base = base * 1024;
194ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        }
195ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
196ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return buf;
197ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
198ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
199ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic char*
200ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_format_create_date( char *buf, size_t buf_size, time_t *time )
201ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
202ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    struct tm *tm;
203ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    tm = localtime(time);
204ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner    if (!tm) {
205ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner        snprintf(buf, buf_size, "<invalid-snapshot-date>");
206ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner    } else {
207ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner        strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm);
208ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner    }
209ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return buf;
210ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
211ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
212ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic char*
213ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_format_vm_clock( char *buf, size_t buf_size, uint64_t vm_clock_nsec )
214ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
215ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t secs = vm_clock_nsec / 1000000000;
216ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snprintf(buf, buf_size, "%02d:%02d:%02d.%03d",
217ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)(secs / 3600),
218ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)((secs / 60) % 60),
219ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)(secs % 60),
220ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)((vm_clock_nsec / 1000000) % 1000));
221ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return buf;
222ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
223ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
224ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Prints a row of the snapshot table to stdout. */
225ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
226ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_print( SnapshotInfo *info )
227ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
228ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char size_buf[8];
229ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char date_buf[21];
230ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char clock_buf[21];
231ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
232ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner    // Note: time_t might be larger than uint32_t.
233ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner    time_t date_sec = info->date_sec;
234ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner
235ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_format_size(size_buf, sizeof(size_buf), info->vm_state_size);
236ef00997efb352a0ab282c9d7bb960be500d3de8bDavid 'Digit' Turner    snapshot_format_create_date(date_buf, sizeof(date_buf), &date_sec);
237ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_format_vm_clock(clock_buf, sizeof(clock_buf), info->vm_clock_nsec);
238ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
239ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    printf(" %-10s%-20s%7s%20s%15s\n",
240ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije           info->id_str, info->name, size_buf, date_buf, clock_buf);
241ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
242ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
243ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Prints table of all snapshots recorded in the file 'fd'.
244ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
245ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
246ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_print_table( int fd, uint32_t nb_snapshots, uint64_t snapshots_offset )
247ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
248ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    printf(" %-10s%-20s%7s%20s%15s\n",
249ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije           "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
250ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
251ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* skip ahead to snapshot data */
252ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, snapshots_offset, SEEK_SET);
253ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
254ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* iterate over snapshot records */
255ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int i;
256ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    for (i = 0; i < nb_snapshots; i++) {
257ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        SnapshotInfo *info = snapshot_info_alloc();
258ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_info_read(fd, info);
259ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_info_print(info);
260ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
261ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_info_free(info);
262ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
263ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
264ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
265ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Validates that 'fd' starts with a correct Qcow 2 header. Prints an error and
266ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * exit()s if validation fails.
267ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
268ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
269ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_validate_qcow_file( int fd )
270ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
271ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read magic number and qcow version (2x4 bytes) */
272ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t magic, version;
273ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &magic, sizeof(magic));
274ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &version, sizeof(version));
275ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&magic);
276ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&version);
277ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
278ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (magic != QCOW_MAGIC) {
279ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("Not a valid Qcow snapshot file (expected magic value '%08x', got '%08x').",
280ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije               QCOW_MAGIC, magic);
281ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
282ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
283ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (version != QCOW_VERSION) {
284ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("Unsupported Qcow version (need %d, got %d).",
285ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije               QCOW_VERSION, version);
286ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
287ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
288ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
289ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
290ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Reads snapshot information from a Qcow2 file header.
291ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
292ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * C.f. QCowHeader in block/qcow2.h for an exact listing of the header
293ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * contents.
294ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
295ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
296ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_read_qcow_header( int fd, uint32_t *nb_snapshots, uint64_t *snapshots_offset )
297ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
298ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_validate_qcow_file(fd);
299ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
300ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* skip non-snapshot related metadata (4x8 + 5x4 = 52 bytes)*/
301ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, 52, SEEK_CUR);
302ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
303ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, nb_snapshots, sizeof(*nb_snapshots));
304ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, snapshots_offset, sizeof(*snapshots_offset));
305ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
306ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* convert to host endianness */
307ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(nb_snapshots);
308ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be64_to_cpus(snapshots_offset);
309ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
310ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
311ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Prints a table with information on the snapshots in the qcow2-formatted file
312ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * 'snapstorage', then exit()s.
313ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
314ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijevoid
315ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_print_and_exit( const char *snapstorage )
316ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
317ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* open snapshot file */
318ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int fd = open(snapstorage, O_RDONLY);
319d80a7861fe5e21e3dcb80480a77b033e6b307dd5David 'Digit' Turner    if (fd < 0) {
320ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("Could not open snapshot file '%s': %s", snapstorage, strerror(errno));
321ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
322ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
323ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
324ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read snapshot info from file header */
325ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t nb_snapshots;
326ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t snapshots_offset;
327ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_read_qcow_header(fd, &nb_snapshots, &snapshots_offset);
328ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
329ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (nb_snapshots > 0) {
330ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        printf("Snapshots in file '%s':\n", snapstorage);
331ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_print_table(fd, nb_snapshots, snapshots_offset);
332ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
333ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    else {
334ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        printf("File '%s' contains no snapshots yet.\n", snapstorage);
335ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
336ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
337ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    close(fd);
338ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    exit(0);
339ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
340