OSDN Git Service

iotests: Test active commit with iothread and background I/O
[qmiga/qemu.git] / tests / qemu-iotests / qcow2.py
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
21 import sys
22
23 from qcow2_format import (
24     QcowHeader,
25     QcowHeaderExtension
26 )
27
28
29 is_json = False
30
31
32 def cmd_dump_header(fd):
33     h = QcowHeader(fd)
34     h.dump(is_json)
35     print()
36     h.dump_extensions(is_json)
37
38
39 def cmd_dump_header_exts(fd):
40     h = QcowHeader(fd)
41     h.dump_extensions(is_json)
42
43
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)
50
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)
55
56     h = QcowHeader(fd)
57     h.__dict__[name] = value
58     h.update(fd)
59
60
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)
67
68     h = QcowHeader(fd)
69     h.extensions.append(QcowHeaderExtension.create(magic,
70                                                    data.encode('ascii')))
71     h.update(fd)
72
73
74 def cmd_add_header_ext_stdio(fd, magic):
75     data = sys.stdin.read()
76     cmd_add_header_ext(fd, magic, data)
77
78
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)
85
86     h = QcowHeader(fd)
87     found = False
88
89     for ex in h.extensions:
90         if ex.magic == magic:
91             found = True
92             h.extensions.remove(ex)
93
94     if not found:
95         print("No such header extension")
96         return
97
98     h.update(fd)
99
100
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)
109
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)
121
122     h.update(fd)
123
124
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'],
136 ]
137
138
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()
154
155
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'))
165
166
167 if __name__ == '__main__':
168     if len(sys.argv) < 3:
169         usage()
170         sys.exit(1)
171
172     is_json = '-j' in sys.argv
173     if is_json:
174         sys.argv.remove('-j')
175
176     main(sys.argv[1], sys.argv[2], sys.argv[3:])