1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3 216306a7bSVladimir Sementsov-Ogievskiy# 316306a7bSVladimir Sementsov-Ogievskiy# Manipulations with qcow2 image 416306a7bSVladimir Sementsov-Ogievskiy# 5*3419ec71SEric Blake# Copyright (C) 2012 Red Hat, Inc. 6*3419ec71SEric Blake# 716306a7bSVladimir Sementsov-Ogievskiy# This program is free software; you can redistribute it and/or modify 816306a7bSVladimir Sementsov-Ogievskiy# it under the terms of the GNU General Public License as published by 916306a7bSVladimir Sementsov-Ogievskiy# the Free Software Foundation; either version 2 of the License, or 1016306a7bSVladimir Sementsov-Ogievskiy# (at your option) any later version. 1116306a7bSVladimir Sementsov-Ogievskiy# 1216306a7bSVladimir Sementsov-Ogievskiy# This program is distributed in the hope that it will be useful, 1316306a7bSVladimir Sementsov-Ogievskiy# but WITHOUT ANY WARRANTY; without even the implied warranty of 1416306a7bSVladimir Sementsov-Ogievskiy# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1516306a7bSVladimir Sementsov-Ogievskiy# GNU General Public License for more details. 1616306a7bSVladimir Sementsov-Ogievskiy# 1716306a7bSVladimir Sementsov-Ogievskiy# You should have received a copy of the GNU General Public License 1816306a7bSVladimir Sementsov-Ogievskiy# along with this program. If not, see <http://www.gnu.org/licenses/>. 1916306a7bSVladimir Sementsov-Ogievskiy# 206e19b3c4SKevin Wolf 216e19b3c4SKevin Wolfimport sys 226e19b3c4SKevin Wolf 23d5262c71SVladimir Sementsov-Ogievskiyfrom qcow2_format import ( 24d5262c71SVladimir Sementsov-Ogievskiy QcowHeader, 25d5262c71SVladimir Sementsov-Ogievskiy QcowHeaderExtension 26d5262c71SVladimir Sementsov-Ogievskiy) 276e19b3c4SKevin Wolf 286e19b3c4SKevin Wolf 296e19b3c4SKevin Wolfdef cmd_dump_header(fd): 306e19b3c4SKevin Wolf h = QcowHeader(fd) 316e19b3c4SKevin Wolf h.dump() 32eeafed5fSVladimir Sementsov-Ogievskiy print() 336e19b3c4SKevin Wolf h.dump_extensions() 346e19b3c4SKevin Wolf 3502756054SVladimir Sementsov-Ogievskiy 361aa6630eSMax Reitzdef cmd_dump_header_exts(fd): 371aa6630eSMax Reitz h = QcowHeader(fd) 381aa6630eSMax Reitz h.dump_extensions() 391aa6630eSMax Reitz 4002756054SVladimir Sementsov-Ogievskiy 41c93331c9SKevin Wolfdef cmd_set_header(fd, name, value): 42c93331c9SKevin Wolf try: 43c93331c9SKevin Wolf value = int(value, 0) 4402756054SVladimir Sementsov-Ogievskiy except ValueError: 45f03868bdSEduardo Habkost print("'%s' is not a valid number" % value) 46c93331c9SKevin Wolf sys.exit(1) 47c93331c9SKevin Wolf 48c93331c9SKevin Wolf fields = (field[2] for field in QcowHeader.fields) 4902756054SVladimir Sementsov-Ogievskiy if name not in fields: 50f03868bdSEduardo Habkost print("'%s' is not a known header field" % name) 51c93331c9SKevin Wolf sys.exit(1) 52c93331c9SKevin Wolf 53c93331c9SKevin Wolf h = QcowHeader(fd) 54c93331c9SKevin Wolf h.__dict__[name] = value 55c93331c9SKevin Wolf h.update(fd) 56c93331c9SKevin Wolf 5702756054SVladimir Sementsov-Ogievskiy 586e19b3c4SKevin Wolfdef cmd_add_header_ext(fd, magic, data): 596e19b3c4SKevin Wolf try: 606e19b3c4SKevin Wolf magic = int(magic, 0) 6102756054SVladimir Sementsov-Ogievskiy except ValueError: 62f03868bdSEduardo Habkost print("'%s' is not a valid magic number" % magic) 636e19b3c4SKevin Wolf sys.exit(1) 646e19b3c4SKevin Wolf 656e19b3c4SKevin Wolf h = QcowHeader(fd) 6602756054SVladimir Sementsov-Ogievskiy h.extensions.append(QcowHeaderExtension.create(magic, 6702756054SVladimir Sementsov-Ogievskiy data.encode('ascii'))) 686e19b3c4SKevin Wolf h.update(fd) 696e19b3c4SKevin Wolf 7002756054SVladimir Sementsov-Ogievskiy 7112ac6d3dSKevin Wolfdef cmd_add_header_ext_stdio(fd, magic): 7212ac6d3dSKevin Wolf data = sys.stdin.read() 7312ac6d3dSKevin Wolf cmd_add_header_ext(fd, magic, data) 7412ac6d3dSKevin Wolf 7502756054SVladimir Sementsov-Ogievskiy 766e19b3c4SKevin Wolfdef cmd_del_header_ext(fd, magic): 776e19b3c4SKevin Wolf try: 786e19b3c4SKevin Wolf magic = int(magic, 0) 7902756054SVladimir Sementsov-Ogievskiy except ValueError: 80f03868bdSEduardo Habkost print("'%s' is not a valid magic number" % magic) 816e19b3c4SKevin Wolf sys.exit(1) 826e19b3c4SKevin Wolf 836e19b3c4SKevin Wolf h = QcowHeader(fd) 846e19b3c4SKevin Wolf found = False 856e19b3c4SKevin Wolf 866e19b3c4SKevin Wolf for ex in h.extensions: 876e19b3c4SKevin Wolf if ex.magic == magic: 886e19b3c4SKevin Wolf found = True 896e19b3c4SKevin Wolf h.extensions.remove(ex) 906e19b3c4SKevin Wolf 916e19b3c4SKevin Wolf if not found: 92f03868bdSEduardo Habkost print("No such header extension") 936e19b3c4SKevin Wolf return 946e19b3c4SKevin Wolf 956e19b3c4SKevin Wolf h.update(fd) 966e19b3c4SKevin Wolf 9702756054SVladimir Sementsov-Ogievskiy 981b2eff62SStefan Hajnoczidef cmd_set_feature_bit(fd, group, bit): 991b2eff62SStefan Hajnoczi try: 1001b2eff62SStefan Hajnoczi bit = int(bit, 0) 1011b2eff62SStefan Hajnoczi if bit < 0 or bit >= 64: 1021b2eff62SStefan Hajnoczi raise ValueError 10302756054SVladimir Sementsov-Ogievskiy except ValueError: 104f03868bdSEduardo Habkost print("'%s' is not a valid bit number in range [0, 64)" % bit) 1051b2eff62SStefan Hajnoczi sys.exit(1) 1061b2eff62SStefan Hajnoczi 1071b2eff62SStefan Hajnoczi h = QcowHeader(fd) 1081b2eff62SStefan Hajnoczi if group == 'incompatible': 1091b2eff62SStefan Hajnoczi h.incompatible_features |= 1 << bit 1101b2eff62SStefan Hajnoczi elif group == 'compatible': 1111b2eff62SStefan Hajnoczi h.compatible_features |= 1 << bit 1121b2eff62SStefan Hajnoczi elif group == 'autoclear': 1131b2eff62SStefan Hajnoczi h.autoclear_features |= 1 << bit 1141b2eff62SStefan Hajnoczi else: 11502756054SVladimir Sementsov-Ogievskiy print("'%s' is not a valid group, try " 11602756054SVladimir Sementsov-Ogievskiy "'incompatible', 'compatible', or 'autoclear'" % group) 1171b2eff62SStefan Hajnoczi sys.exit(1) 1181b2eff62SStefan Hajnoczi 1191b2eff62SStefan Hajnoczi h.update(fd) 1201b2eff62SStefan Hajnoczi 12102756054SVladimir Sementsov-Ogievskiy 1226e19b3c4SKevin Wolfcmds = [ 12302756054SVladimir Sementsov-Ogievskiy ['dump-header', cmd_dump_header, 0, 12402756054SVladimir Sementsov-Ogievskiy 'Dump image header and header extensions'], 12502756054SVladimir Sementsov-Ogievskiy ['dump-header-exts', cmd_dump_header_exts, 0, 12602756054SVladimir Sementsov-Ogievskiy 'Dump image header extensions'], 127c93331c9SKevin Wolf ['set-header', cmd_set_header, 2, 'Set a field in the header'], 1286e19b3c4SKevin Wolf ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'], 12902756054SVladimir Sementsov-Ogievskiy ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 13002756054SVladimir Sementsov-Ogievskiy 'Add a header extension, data from stdin'], 1316e19b3c4SKevin Wolf ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'], 1321b2eff62SStefan Hajnoczi ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], 1336e19b3c4SKevin Wolf] 1346e19b3c4SKevin Wolf 13502756054SVladimir Sementsov-Ogievskiy 1366e19b3c4SKevin Wolfdef main(filename, cmd, args): 1376e19b3c4SKevin Wolf fd = open(filename, "r+b") 1386e19b3c4SKevin Wolf try: 1396e19b3c4SKevin Wolf for name, handler, num_args, desc in cmds: 1406e19b3c4SKevin Wolf if name != cmd: 1416e19b3c4SKevin Wolf continue 1426e19b3c4SKevin Wolf elif len(args) != num_args: 1436e19b3c4SKevin Wolf usage() 1446e19b3c4SKevin Wolf return 1456e19b3c4SKevin Wolf else: 1466e19b3c4SKevin Wolf handler(fd, *args) 1476e19b3c4SKevin Wolf return 148f03868bdSEduardo Habkost print("Unknown command '%s'" % cmd) 1496e19b3c4SKevin Wolf finally: 1506e19b3c4SKevin Wolf fd.close() 1516e19b3c4SKevin Wolf 15202756054SVladimir Sementsov-Ogievskiy 1536e19b3c4SKevin Wolfdef usage(): 154f03868bdSEduardo Habkost print("Usage: %s <file> <cmd> [<arg>, ...]" % sys.argv[0]) 155f03868bdSEduardo Habkost print("") 156f03868bdSEduardo Habkost print("Supported commands:") 1576e19b3c4SKevin Wolf for name, handler, num_args, desc in cmds: 158f03868bdSEduardo Habkost print(" %-20s - %s" % (name, desc)) 1596e19b3c4SKevin Wolf 16002756054SVladimir Sementsov-Ogievskiy 161d2ef210cSKevin Wolfif __name__ == '__main__': 1626e19b3c4SKevin Wolf if len(sys.argv) < 3: 1636e19b3c4SKevin Wolf usage() 1646e19b3c4SKevin Wolf sys.exit(1) 1656e19b3c4SKevin Wolf 1666e19b3c4SKevin Wolf main(sys.argv[1], sys.argv[2], sys.argv[3:]) 167