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