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