1#!/usr/bin/env python3 2# 3# Manipulations with qcow2 image 4# 5# Copyright (C) 2012 Red Hat, Inc. 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 2 of the License, or 10# (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program. If not, see <http://www.gnu.org/licenses/>. 19# 20 21import sys 22 23from qcow2_format import ( 24 QcowHeader, 25 QcowHeaderExtension 26) 27 28 29def cmd_dump_header(fd): 30 h = QcowHeader(fd) 31 h.dump() 32 print() 33 h.dump_extensions() 34 35 36def cmd_dump_header_exts(fd): 37 h = QcowHeader(fd) 38 h.dump_extensions() 39 40 41def cmd_set_header(fd, name, value): 42 try: 43 value = int(value, 0) 44 except ValueError: 45 print("'%s' is not a valid number" % value) 46 sys.exit(1) 47 48 fields = (field[2] for field in QcowHeader.fields) 49 if name not in fields: 50 print("'%s' is not a known header field" % name) 51 sys.exit(1) 52 53 h = QcowHeader(fd) 54 h.__dict__[name] = value 55 h.update(fd) 56 57 58def cmd_add_header_ext(fd, magic, data): 59 try: 60 magic = int(magic, 0) 61 except ValueError: 62 print("'%s' is not a valid magic number" % magic) 63 sys.exit(1) 64 65 h = QcowHeader(fd) 66 h.extensions.append(QcowHeaderExtension.create(magic, 67 data.encode('ascii'))) 68 h.update(fd) 69 70 71def cmd_add_header_ext_stdio(fd, magic): 72 data = sys.stdin.read() 73 cmd_add_header_ext(fd, magic, data) 74 75 76def cmd_del_header_ext(fd, magic): 77 try: 78 magic = int(magic, 0) 79 except ValueError: 80 print("'%s' is not a valid magic number" % magic) 81 sys.exit(1) 82 83 h = QcowHeader(fd) 84 found = False 85 86 for ex in h.extensions: 87 if ex.magic == magic: 88 found = True 89 h.extensions.remove(ex) 90 91 if not found: 92 print("No such header extension") 93 return 94 95 h.update(fd) 96 97 98def cmd_set_feature_bit(fd, group, bit): 99 try: 100 bit = int(bit, 0) 101 if bit < 0 or bit >= 64: 102 raise ValueError 103 except ValueError: 104 print("'%s' is not a valid bit number in range [0, 64)" % bit) 105 sys.exit(1) 106 107 h = QcowHeader(fd) 108 if group == 'incompatible': 109 h.incompatible_features |= 1 << bit 110 elif group == 'compatible': 111 h.compatible_features |= 1 << bit 112 elif group == 'autoclear': 113 h.autoclear_features |= 1 << bit 114 else: 115 print("'%s' is not a valid group, try " 116 "'incompatible', 'compatible', or 'autoclear'" % group) 117 sys.exit(1) 118 119 h.update(fd) 120 121 122cmds = [ 123 ['dump-header', cmd_dump_header, 0, 124 'Dump image header and header extensions'], 125 ['dump-header-exts', cmd_dump_header_exts, 0, 126 'Dump image header extensions'], 127 ['set-header', cmd_set_header, 2, 'Set a field in the header'], 128 ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'], 129 ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 130 'Add a header extension, data from stdin'], 131 ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'], 132 ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], 133] 134 135 136def main(filename, cmd, args): 137 fd = open(filename, "r+b") 138 try: 139 for name, handler, num_args, desc in cmds: 140 if name != cmd: 141 continue 142 elif len(args) != num_args: 143 usage() 144 return 145 else: 146 handler(fd, *args) 147 return 148 print("Unknown command '%s'" % cmd) 149 finally: 150 fd.close() 151 152 153def usage(): 154 print("Usage: %s <file> <cmd> [<arg>, ...]" % sys.argv[0]) 155 print("") 156 print("Supported commands:") 157 for name, handler, num_args, desc in cmds: 158 print(" %-20s - %s" % (name, desc)) 159 160 161if __name__ == '__main__': 162 if len(sys.argv) < 3: 163 usage() 164 sys.exit(1) 165 166 main(sys.argv[1], sys.argv[2], sys.argv[3:]) 167