xref: /openbmc/qemu/tests/qemu-iotests/qcow2.py (revision 66e01f1cdc9663660201cced4df8ec0a28937919)
1903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3
216306a7bSVladimir Sementsov-Ogievskiy#
316306a7bSVladimir Sementsov-Ogievskiy# Manipulations with qcow2 image
416306a7bSVladimir Sementsov-Ogievskiy#
53419ec71SEric Blake# Copyright (C) 2012 Red Hat, Inc.
63419ec71SEric 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
29*2c6d9ca4SAndrey Shinkevichis_json = False
30*2c6d9ca4SAndrey Shinkevich
31*2c6d9ca4SAndrey Shinkevich
326e19b3c4SKevin Wolfdef cmd_dump_header(fd):
336e19b3c4SKevin Wolf    h = QcowHeader(fd)
34*2c6d9ca4SAndrey Shinkevich    h.dump(is_json)
35eeafed5fSVladimir Sementsov-Ogievskiy    print()
36*2c6d9ca4SAndrey Shinkevich    h.dump_extensions(is_json)
376e19b3c4SKevin Wolf
3802756054SVladimir Sementsov-Ogievskiy
391aa6630eSMax Reitzdef cmd_dump_header_exts(fd):
401aa6630eSMax Reitz    h = QcowHeader(fd)
41*2c6d9ca4SAndrey Shinkevich    h.dump_extensions(is_json)
421aa6630eSMax Reitz
4302756054SVladimir Sementsov-Ogievskiy
44c93331c9SKevin Wolfdef cmd_set_header(fd, name, value):
45c93331c9SKevin Wolf    try:
46c93331c9SKevin Wolf        value = int(value, 0)
4702756054SVladimir Sementsov-Ogievskiy    except ValueError:
48f03868bdSEduardo Habkost        print("'%s' is not a valid number" % value)
49c93331c9SKevin Wolf        sys.exit(1)
50c93331c9SKevin Wolf
51c93331c9SKevin Wolf    fields = (field[2] for field in QcowHeader.fields)
5202756054SVladimir Sementsov-Ogievskiy    if name not in fields:
53f03868bdSEduardo Habkost        print("'%s' is not a known header field" % name)
54c93331c9SKevin Wolf        sys.exit(1)
55c93331c9SKevin Wolf
56c93331c9SKevin Wolf    h = QcowHeader(fd)
57c93331c9SKevin Wolf    h.__dict__[name] = value
58c93331c9SKevin Wolf    h.update(fd)
59c93331c9SKevin Wolf
6002756054SVladimir Sementsov-Ogievskiy
616e19b3c4SKevin Wolfdef cmd_add_header_ext(fd, magic, data):
626e19b3c4SKevin Wolf    try:
636e19b3c4SKevin Wolf        magic = int(magic, 0)
6402756054SVladimir Sementsov-Ogievskiy    except ValueError:
65f03868bdSEduardo Habkost        print("'%s' is not a valid magic number" % magic)
666e19b3c4SKevin Wolf        sys.exit(1)
676e19b3c4SKevin Wolf
686e19b3c4SKevin Wolf    h = QcowHeader(fd)
6902756054SVladimir Sementsov-Ogievskiy    h.extensions.append(QcowHeaderExtension.create(magic,
7002756054SVladimir Sementsov-Ogievskiy                                                   data.encode('ascii')))
716e19b3c4SKevin Wolf    h.update(fd)
726e19b3c4SKevin Wolf
7302756054SVladimir Sementsov-Ogievskiy
7412ac6d3dSKevin Wolfdef cmd_add_header_ext_stdio(fd, magic):
7512ac6d3dSKevin Wolf    data = sys.stdin.read()
7612ac6d3dSKevin Wolf    cmd_add_header_ext(fd, magic, data)
7712ac6d3dSKevin Wolf
7802756054SVladimir Sementsov-Ogievskiy
796e19b3c4SKevin Wolfdef cmd_del_header_ext(fd, magic):
806e19b3c4SKevin Wolf    try:
816e19b3c4SKevin Wolf        magic = int(magic, 0)
8202756054SVladimir Sementsov-Ogievskiy    except ValueError:
83f03868bdSEduardo Habkost        print("'%s' is not a valid magic number" % magic)
846e19b3c4SKevin Wolf        sys.exit(1)
856e19b3c4SKevin Wolf
866e19b3c4SKevin Wolf    h = QcowHeader(fd)
876e19b3c4SKevin Wolf    found = False
886e19b3c4SKevin Wolf
896e19b3c4SKevin Wolf    for ex in h.extensions:
906e19b3c4SKevin Wolf        if ex.magic == magic:
916e19b3c4SKevin Wolf            found = True
926e19b3c4SKevin Wolf            h.extensions.remove(ex)
936e19b3c4SKevin Wolf
946e19b3c4SKevin Wolf    if not found:
95f03868bdSEduardo Habkost        print("No such header extension")
966e19b3c4SKevin Wolf        return
976e19b3c4SKevin Wolf
986e19b3c4SKevin Wolf    h.update(fd)
996e19b3c4SKevin Wolf
10002756054SVladimir Sementsov-Ogievskiy
1011b2eff62SStefan Hajnoczidef cmd_set_feature_bit(fd, group, bit):
1021b2eff62SStefan Hajnoczi    try:
1031b2eff62SStefan Hajnoczi        bit = int(bit, 0)
1041b2eff62SStefan Hajnoczi        if bit < 0 or bit >= 64:
1051b2eff62SStefan Hajnoczi            raise ValueError
10602756054SVladimir Sementsov-Ogievskiy    except ValueError:
107f03868bdSEduardo Habkost        print("'%s' is not a valid bit number in range [0, 64)" % bit)
1081b2eff62SStefan Hajnoczi        sys.exit(1)
1091b2eff62SStefan Hajnoczi
1101b2eff62SStefan Hajnoczi    h = QcowHeader(fd)
1111b2eff62SStefan Hajnoczi    if group == 'incompatible':
1121b2eff62SStefan Hajnoczi        h.incompatible_features |= 1 << bit
1131b2eff62SStefan Hajnoczi    elif group == 'compatible':
1141b2eff62SStefan Hajnoczi        h.compatible_features |= 1 << bit
1151b2eff62SStefan Hajnoczi    elif group == 'autoclear':
1161b2eff62SStefan Hajnoczi        h.autoclear_features |= 1 << bit
1171b2eff62SStefan Hajnoczi    else:
11802756054SVladimir Sementsov-Ogievskiy        print("'%s' is not a valid group, try "
11902756054SVladimir Sementsov-Ogievskiy              "'incompatible', 'compatible', or 'autoclear'" % group)
1201b2eff62SStefan Hajnoczi        sys.exit(1)
1211b2eff62SStefan Hajnoczi
1221b2eff62SStefan Hajnoczi    h.update(fd)
1231b2eff62SStefan Hajnoczi
12402756054SVladimir Sementsov-Ogievskiy
1256e19b3c4SKevin Wolfcmds = [
12602756054SVladimir Sementsov-Ogievskiy    ['dump-header', cmd_dump_header, 0,
12702756054SVladimir Sementsov-Ogievskiy     'Dump image header and header extensions'],
12802756054SVladimir Sementsov-Ogievskiy    ['dump-header-exts', cmd_dump_header_exts, 0,
12902756054SVladimir Sementsov-Ogievskiy     'Dump image header extensions'],
130c93331c9SKevin Wolf    ['set-header', cmd_set_header, 2, 'Set a field in the header'],
1316e19b3c4SKevin Wolf    ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'],
13202756054SVladimir Sementsov-Ogievskiy    ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1,
13302756054SVladimir Sementsov-Ogievskiy     'Add a header extension, data from stdin'],
1346e19b3c4SKevin Wolf    ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'],
1351b2eff62SStefan Hajnoczi    ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
1366e19b3c4SKevin Wolf]
1376e19b3c4SKevin Wolf
13802756054SVladimir Sementsov-Ogievskiy
1396e19b3c4SKevin Wolfdef main(filename, cmd, args):
1406e19b3c4SKevin Wolf    fd = open(filename, "r+b")
1416e19b3c4SKevin Wolf    try:
1426e19b3c4SKevin Wolf        for name, handler, num_args, desc in cmds:
1436e19b3c4SKevin Wolf            if name != cmd:
1446e19b3c4SKevin Wolf                continue
1456e19b3c4SKevin Wolf            elif len(args) != num_args:
1466e19b3c4SKevin Wolf                usage()
1476e19b3c4SKevin Wolf                return
1486e19b3c4SKevin Wolf            else:
1496e19b3c4SKevin Wolf                handler(fd, *args)
1506e19b3c4SKevin Wolf                return
151f03868bdSEduardo Habkost        print("Unknown command '%s'" % cmd)
1526e19b3c4SKevin Wolf    finally:
1536e19b3c4SKevin Wolf        fd.close()
1546e19b3c4SKevin Wolf
15502756054SVladimir Sementsov-Ogievskiy
1566e19b3c4SKevin Wolfdef usage():
157*2c6d9ca4SAndrey Shinkevich    print("Usage: %s <file> <cmd> [<arg>, ...] [<key>, ...]" % sys.argv[0])
158f03868bdSEduardo Habkost    print("")
159f03868bdSEduardo Habkost    print("Supported commands:")
1606e19b3c4SKevin Wolf    for name, handler, num_args, desc in cmds:
161f03868bdSEduardo Habkost        print("    %-20s - %s" % (name, desc))
162*2c6d9ca4SAndrey Shinkevich    print("")
163*2c6d9ca4SAndrey Shinkevich    print("Supported keys:")
164*2c6d9ca4SAndrey Shinkevich    print("    %-20s - %s" % ('-j', 'Dump in JSON format'))
1656e19b3c4SKevin Wolf
16602756054SVladimir Sementsov-Ogievskiy
167d2ef210cSKevin Wolfif __name__ == '__main__':
1686e19b3c4SKevin Wolf    if len(sys.argv) < 3:
1696e19b3c4SKevin Wolf        usage()
1706e19b3c4SKevin Wolf        sys.exit(1)
1716e19b3c4SKevin Wolf
172*2c6d9ca4SAndrey Shinkevich    is_json = '-j' in sys.argv
173*2c6d9ca4SAndrey Shinkevich    if is_json:
174*2c6d9ca4SAndrey Shinkevich        sys.argv.remove('-j')
175*2c6d9ca4SAndrey Shinkevich
1766e19b3c4SKevin Wolf    main(sys.argv[1], sys.argv[2], sys.argv[3:])
177