1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3 216306a7bSVladimir Sementsov-Ogievskiy# 316306a7bSVladimir Sementsov-Ogievskiy# Manipulations with qcow2 image 416306a7bSVladimir Sementsov-Ogievskiy# 516306a7bSVladimir Sementsov-Ogievskiy# This program is free software; you can redistribute it and/or modify 616306a7bSVladimir Sementsov-Ogievskiy# it under the terms of the GNU General Public License as published by 716306a7bSVladimir Sementsov-Ogievskiy# the Free Software Foundation; either version 2 of the License, or 816306a7bSVladimir Sementsov-Ogievskiy# (at your option) any later version. 916306a7bSVladimir Sementsov-Ogievskiy# 1016306a7bSVladimir Sementsov-Ogievskiy# This program is distributed in the hope that it will be useful, 1116306a7bSVladimir Sementsov-Ogievskiy# but WITHOUT ANY WARRANTY; without even the implied warranty of 1216306a7bSVladimir Sementsov-Ogievskiy# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1316306a7bSVladimir Sementsov-Ogievskiy# GNU General Public License for more details. 1416306a7bSVladimir Sementsov-Ogievskiy# 1516306a7bSVladimir Sementsov-Ogievskiy# You should have received a copy of the GNU General Public License 1616306a7bSVladimir Sementsov-Ogievskiy# along with this program. If not, see <http://www.gnu.org/licenses/>. 1716306a7bSVladimir Sementsov-Ogievskiy# 186e19b3c4SKevin Wolf 196e19b3c4SKevin Wolfimport sys 206e19b3c4SKevin Wolf 21d5262c71SVladimir Sementsov-Ogievskiyfrom qcow2_format import ( 22d5262c71SVladimir Sementsov-Ogievskiy QcowHeader, 23d5262c71SVladimir Sementsov-Ogievskiy QcowHeaderExtension 24d5262c71SVladimir Sementsov-Ogievskiy) 256e19b3c4SKevin Wolf 266e19b3c4SKevin Wolf 276e19b3c4SKevin Wolfdef cmd_dump_header(fd): 286e19b3c4SKevin Wolf h = QcowHeader(fd) 296e19b3c4SKevin Wolf h.dump() 30*eeafed5fSVladimir Sementsov-Ogievskiy print() 316e19b3c4SKevin Wolf h.dump_extensions() 326e19b3c4SKevin Wolf 3302756054SVladimir Sementsov-Ogievskiy 341aa6630eSMax Reitzdef cmd_dump_header_exts(fd): 351aa6630eSMax Reitz h = QcowHeader(fd) 361aa6630eSMax Reitz h.dump_extensions() 371aa6630eSMax Reitz 3802756054SVladimir Sementsov-Ogievskiy 39c93331c9SKevin Wolfdef cmd_set_header(fd, name, value): 40c93331c9SKevin Wolf try: 41c93331c9SKevin Wolf value = int(value, 0) 4202756054SVladimir Sementsov-Ogievskiy except ValueError: 43f03868bdSEduardo Habkost print("'%s' is not a valid number" % value) 44c93331c9SKevin Wolf sys.exit(1) 45c93331c9SKevin Wolf 46c93331c9SKevin Wolf fields = (field[2] for field in QcowHeader.fields) 4702756054SVladimir Sementsov-Ogievskiy if name not in fields: 48f03868bdSEduardo Habkost print("'%s' is not a known header field" % name) 49c93331c9SKevin Wolf sys.exit(1) 50c93331c9SKevin Wolf 51c93331c9SKevin Wolf h = QcowHeader(fd) 52c93331c9SKevin Wolf h.__dict__[name] = value 53c93331c9SKevin Wolf h.update(fd) 54c93331c9SKevin Wolf 5502756054SVladimir Sementsov-Ogievskiy 566e19b3c4SKevin Wolfdef cmd_add_header_ext(fd, magic, data): 576e19b3c4SKevin Wolf try: 586e19b3c4SKevin Wolf magic = int(magic, 0) 5902756054SVladimir Sementsov-Ogievskiy except ValueError: 60f03868bdSEduardo Habkost print("'%s' is not a valid magic number" % magic) 616e19b3c4SKevin Wolf sys.exit(1) 626e19b3c4SKevin Wolf 636e19b3c4SKevin Wolf h = QcowHeader(fd) 6402756054SVladimir Sementsov-Ogievskiy h.extensions.append(QcowHeaderExtension.create(magic, 6502756054SVladimir Sementsov-Ogievskiy data.encode('ascii'))) 666e19b3c4SKevin Wolf h.update(fd) 676e19b3c4SKevin Wolf 6802756054SVladimir Sementsov-Ogievskiy 6912ac6d3dSKevin Wolfdef cmd_add_header_ext_stdio(fd, magic): 7012ac6d3dSKevin Wolf data = sys.stdin.read() 7112ac6d3dSKevin Wolf cmd_add_header_ext(fd, magic, data) 7212ac6d3dSKevin Wolf 7302756054SVladimir Sementsov-Ogievskiy 746e19b3c4SKevin Wolfdef cmd_del_header_ext(fd, magic): 756e19b3c4SKevin Wolf try: 766e19b3c4SKevin Wolf magic = int(magic, 0) 7702756054SVladimir Sementsov-Ogievskiy except ValueError: 78f03868bdSEduardo Habkost print("'%s' is not a valid magic number" % magic) 796e19b3c4SKevin Wolf sys.exit(1) 806e19b3c4SKevin Wolf 816e19b3c4SKevin Wolf h = QcowHeader(fd) 826e19b3c4SKevin Wolf found = False 836e19b3c4SKevin Wolf 846e19b3c4SKevin Wolf for ex in h.extensions: 856e19b3c4SKevin Wolf if ex.magic == magic: 866e19b3c4SKevin Wolf found = True 876e19b3c4SKevin Wolf h.extensions.remove(ex) 886e19b3c4SKevin Wolf 896e19b3c4SKevin Wolf if not found: 90f03868bdSEduardo Habkost print("No such header extension") 916e19b3c4SKevin Wolf return 926e19b3c4SKevin Wolf 936e19b3c4SKevin Wolf h.update(fd) 946e19b3c4SKevin Wolf 9502756054SVladimir Sementsov-Ogievskiy 961b2eff62SStefan Hajnoczidef cmd_set_feature_bit(fd, group, bit): 971b2eff62SStefan Hajnoczi try: 981b2eff62SStefan Hajnoczi bit = int(bit, 0) 991b2eff62SStefan Hajnoczi if bit < 0 or bit >= 64: 1001b2eff62SStefan Hajnoczi raise ValueError 10102756054SVladimir Sementsov-Ogievskiy except ValueError: 102f03868bdSEduardo Habkost print("'%s' is not a valid bit number in range [0, 64)" % bit) 1031b2eff62SStefan Hajnoczi sys.exit(1) 1041b2eff62SStefan Hajnoczi 1051b2eff62SStefan Hajnoczi h = QcowHeader(fd) 1061b2eff62SStefan Hajnoczi if group == 'incompatible': 1071b2eff62SStefan Hajnoczi h.incompatible_features |= 1 << bit 1081b2eff62SStefan Hajnoczi elif group == 'compatible': 1091b2eff62SStefan Hajnoczi h.compatible_features |= 1 << bit 1101b2eff62SStefan Hajnoczi elif group == 'autoclear': 1111b2eff62SStefan Hajnoczi h.autoclear_features |= 1 << bit 1121b2eff62SStefan Hajnoczi else: 11302756054SVladimir Sementsov-Ogievskiy print("'%s' is not a valid group, try " 11402756054SVladimir Sementsov-Ogievskiy "'incompatible', 'compatible', or 'autoclear'" % group) 1151b2eff62SStefan Hajnoczi sys.exit(1) 1161b2eff62SStefan Hajnoczi 1171b2eff62SStefan Hajnoczi h.update(fd) 1181b2eff62SStefan Hajnoczi 11902756054SVladimir Sementsov-Ogievskiy 1206e19b3c4SKevin Wolfcmds = [ 12102756054SVladimir Sementsov-Ogievskiy ['dump-header', cmd_dump_header, 0, 12202756054SVladimir Sementsov-Ogievskiy 'Dump image header and header extensions'], 12302756054SVladimir Sementsov-Ogievskiy ['dump-header-exts', cmd_dump_header_exts, 0, 12402756054SVladimir Sementsov-Ogievskiy 'Dump image header extensions'], 125c93331c9SKevin Wolf ['set-header', cmd_set_header, 2, 'Set a field in the header'], 1266e19b3c4SKevin Wolf ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'], 12702756054SVladimir Sementsov-Ogievskiy ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 12802756054SVladimir Sementsov-Ogievskiy 'Add a header extension, data from stdin'], 1296e19b3c4SKevin Wolf ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'], 1301b2eff62SStefan Hajnoczi ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], 1316e19b3c4SKevin Wolf] 1326e19b3c4SKevin Wolf 13302756054SVladimir Sementsov-Ogievskiy 1346e19b3c4SKevin Wolfdef main(filename, cmd, args): 1356e19b3c4SKevin Wolf fd = open(filename, "r+b") 1366e19b3c4SKevin Wolf try: 1376e19b3c4SKevin Wolf for name, handler, num_args, desc in cmds: 1386e19b3c4SKevin Wolf if name != cmd: 1396e19b3c4SKevin Wolf continue 1406e19b3c4SKevin Wolf elif len(args) != num_args: 1416e19b3c4SKevin Wolf usage() 1426e19b3c4SKevin Wolf return 1436e19b3c4SKevin Wolf else: 1446e19b3c4SKevin Wolf handler(fd, *args) 1456e19b3c4SKevin Wolf return 146f03868bdSEduardo Habkost print("Unknown command '%s'" % cmd) 1476e19b3c4SKevin Wolf finally: 1486e19b3c4SKevin Wolf fd.close() 1496e19b3c4SKevin Wolf 15002756054SVladimir Sementsov-Ogievskiy 1516e19b3c4SKevin Wolfdef usage(): 152f03868bdSEduardo Habkost print("Usage: %s <file> <cmd> [<arg>, ...]" % sys.argv[0]) 153f03868bdSEduardo Habkost print("") 154f03868bdSEduardo Habkost print("Supported commands:") 1556e19b3c4SKevin Wolf for name, handler, num_args, desc in cmds: 156f03868bdSEduardo Habkost print(" %-20s - %s" % (name, desc)) 1576e19b3c4SKevin Wolf 15802756054SVladimir Sementsov-Ogievskiy 159d2ef210cSKevin Wolfif __name__ == '__main__': 1606e19b3c4SKevin Wolf if len(sys.argv) < 3: 1616e19b3c4SKevin Wolf usage() 1626e19b3c4SKevin Wolf sys.exit(1) 1636e19b3c4SKevin Wolf 1646e19b3c4SKevin Wolf main(sys.argv[1], sys.argv[2], sys.argv[3:]) 165