2
0

qcow2.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. import sys
  21. from qcow2_format import (
  22. QcowHeader,
  23. QcowHeaderExtension
  24. )
  25. is_json = False
  26. def cmd_dump_header(fd):
  27. h = QcowHeader(fd)
  28. h.dump(is_json)
  29. print()
  30. h.dump_extensions(is_json)
  31. def cmd_dump_header_exts(fd):
  32. h = QcowHeader(fd)
  33. h.dump_extensions(is_json)
  34. def cmd_set_header(fd, name, value):
  35. try:
  36. value = int(value, 0)
  37. except ValueError:
  38. print("'%s' is not a valid number" % value)
  39. sys.exit(1)
  40. fields = (field[2] for field in QcowHeader.fields)
  41. if name not in fields:
  42. print("'%s' is not a known header field" % name)
  43. sys.exit(1)
  44. h = QcowHeader(fd)
  45. h.__dict__[name] = value
  46. h.update(fd)
  47. def cmd_add_header_ext(fd, magic, data):
  48. try:
  49. magic = int(magic, 0)
  50. except ValueError:
  51. print("'%s' is not a valid magic number" % magic)
  52. sys.exit(1)
  53. h = QcowHeader(fd)
  54. h.extensions.append(QcowHeaderExtension.create(magic,
  55. data.encode('ascii')))
  56. h.update(fd)
  57. def cmd_add_header_ext_stdio(fd, magic):
  58. data = sys.stdin.read()
  59. cmd_add_header_ext(fd, magic, data)
  60. def cmd_del_header_ext(fd, magic):
  61. try:
  62. magic = int(magic, 0)
  63. except ValueError:
  64. print("'%s' is not a valid magic number" % magic)
  65. sys.exit(1)
  66. h = QcowHeader(fd)
  67. found = False
  68. for ex in h.extensions:
  69. if ex.magic == magic:
  70. found = True
  71. h.extensions.remove(ex)
  72. if not found:
  73. print("No such header extension")
  74. return
  75. h.update(fd)
  76. def cmd_set_feature_bit(fd, group, bit):
  77. try:
  78. bit = int(bit, 0)
  79. if bit < 0 or bit >= 64:
  80. raise ValueError
  81. except ValueError:
  82. print("'%s' is not a valid bit number in range [0, 64)" % bit)
  83. sys.exit(1)
  84. h = QcowHeader(fd)
  85. if group == 'incompatible':
  86. h.incompatible_features |= 1 << bit
  87. elif group == 'compatible':
  88. h.compatible_features |= 1 << bit
  89. elif group == 'autoclear':
  90. h.autoclear_features |= 1 << bit
  91. else:
  92. print("'%s' is not a valid group, try "
  93. "'incompatible', 'compatible', or 'autoclear'" % group)
  94. sys.exit(1)
  95. h.update(fd)
  96. cmds = [
  97. ['dump-header', cmd_dump_header, 0,
  98. 'Dump image header and header extensions'],
  99. ['dump-header-exts', cmd_dump_header_exts, 0,
  100. 'Dump image header extensions'],
  101. ['set-header', cmd_set_header, 2, 'Set a field in the header'],
  102. ['add-header-ext', cmd_add_header_ext, 2, 'Add a header extension'],
  103. ['add-header-ext-stdio', cmd_add_header_ext_stdio, 1,
  104. 'Add a header extension, data from stdin'],
  105. ['del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension'],
  106. ['set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
  107. ]
  108. def main(filename, cmd, args):
  109. fd = open(filename, "r+b")
  110. try:
  111. for name, handler, num_args, desc in cmds:
  112. if name != cmd:
  113. continue
  114. elif len(args) != num_args:
  115. usage()
  116. return
  117. else:
  118. handler(fd, *args)
  119. return
  120. print("Unknown command '%s'" % cmd)
  121. finally:
  122. fd.close()
  123. def usage():
  124. print("Usage: %s <file> <cmd> [<arg>, ...] [<key>, ...]" % sys.argv[0])
  125. print("")
  126. print("Supported commands:")
  127. for name, handler, num_args, desc in cmds:
  128. print(" %-20s - %s" % (name, desc))
  129. print("")
  130. print("Supported keys:")
  131. print(" %-20s - %s" % ('-j', 'Dump in JSON format'))
  132. if __name__ == '__main__':
  133. if len(sys.argv) < 3:
  134. usage()
  135. sys.exit(1)
  136. is_json = '-j' in sys.argv
  137. if is_json:
  138. sys.argv.remove('-j')
  139. main(sys.argv[1], sys.argv[2], sys.argv[3:])