Merge tag 'qemu-macppc-20230206' of https://github.com/mcayland/qemu into staging
[qemu.git] / tests / qemu-iotests / qcow2.py
blob77ca59cc663dfb0cfdf35a472864fa656e41633f
1 #!/usr/bin/env python3
3 # Manipulations with qcow2 image
5 # Copyright (C) 2012 Red Hat, Inc.
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.
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.
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/>.
21 import sys
23 from qcow2_format import (
24 QcowHeader,
25 QcowHeaderExtension
29 is_json = False
32 def cmd_dump_header(fd):
33 h = QcowHeader(fd)
34 h.dump(is_json)
35 print()
36 h.dump_extensions(is_json)
39 def cmd_dump_header_exts(fd):
40 h = QcowHeader(fd)
41 h.dump_extensions(is_json)
44 def cmd_set_header(fd, name, value):
45 try:
46 value = int(value, 0)
47 except ValueError:
48 print("'%s' is not a valid number" % value)
49 sys.exit(1)
51 fields = (field[2] for field in QcowHeader.fields)
52 if name not in fields:
53 print("'%s' is not a known header field" % name)
54 sys.exit(1)
56 h = QcowHeader(fd)
57 h.__dict__[name] = value
58 h.update(fd)
61 def cmd_add_header_ext(fd, magic, data):
62 try:
63 magic = int(magic, 0)
64 except ValueError:
65 print("'%s' is not a valid magic number" % magic)
66 sys.exit(1)
68 h = QcowHeader(fd)
69 h.extensions.append(QcowHeaderExtension.create(magic,
70 data.encode('ascii')))
71 h.update(fd)
74 def cmd_add_header_ext_stdio(fd, magic):
75 data = sys.stdin.read()
76 cmd_add_header_ext(fd, magic, data)
79 def cmd_del_header_ext(fd, magic):
80 try:
81 magic = int(magic, 0)
82 except ValueError:
83 print("'%s' is not a valid magic number" % magic)
84 sys.exit(1)
86 h = QcowHeader(fd)
87 found = False
89 for ex in h.extensions:
90 if ex.magic == magic:
91 found = True
92 h.extensions.remove(ex)
94 if not found:
95 print("No such header extension")
96 return
98 h.update(fd)
101 def cmd_set_feature_bit(fd, group, bit):
102 try:
103 bit = int(bit, 0)
104 if bit < 0 or bit >= 64:
105 raise ValueError
106 except ValueError:
107 print("'%s' is not a valid bit number in range [0, 64)" % bit)
108 sys.exit(1)
110 h = QcowHeader(fd)
111 if group == 'incompatible':
112 h.incompatible_features |= 1 << bit
113 elif group == 'compatible':
114 h.compatible_features |= 1 << bit
115 elif group == 'autoclear':
116 h.autoclear_features |= 1 << bit
117 else:
118 print("'%s' is not a valid group, try "
119 "'incompatible', 'compatible', or 'autoclear'" % group)
120 sys.exit(1)
122 h.update(fd)
125 cmds = [
126 ['dump-header', cmd_dump_header, 0,
127 'Dump image header and header extensions'],
128 ['dump-header-exts', cmd_dump_header_exts, 0,
129 'Dump image header extensions'],
130 ['set-header', cmd_set_header, 2, 'Set a field in the header'],
131 ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'],
132 ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1,
133 'Add a header extension, data from stdin'],
134 ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'],
135 ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
139 def main(filename, cmd, args):
140 fd = open(filename, "r+b")
141 try:
142 for name, handler, num_args, desc in cmds:
143 if name != cmd:
144 continue
145 elif len(args) != num_args:
146 usage()
147 return
148 else:
149 handler(fd, *args)
150 return
151 print("Unknown command '%s'" % cmd)
152 finally:
153 fd.close()
156 def usage():
157 print("Usage: %s <file> <cmd> [<arg>, ...] [<key>, ...]" % sys.argv[0])
158 print("")
159 print("Supported commands:")
160 for name, handler, num_args, desc in cmds:
161 print(" %-20s - %s" % (name, desc))
162 print("")
163 print("Supported keys:")
164 print(" %-20s - %s" % ('-j', 'Dump in JSON format'))
167 if __name__ == '__main__':
168 if len(sys.argv) < 3:
169 usage()
170 sys.exit(1)
172 is_json = '-j' in sys.argv
173 if is_json:
174 sys.argv.remove('-j')
176 main(sys.argv[1], sys.argv[2], sys.argv[3:])