rpm2cpio.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Lightweight RPM to CPIO converter.
  5. # Copyright © 2008-2017 Rudá Moura. All rights reserved.
  6. #
  7. '''Extract cpio archive from RPM package.
  8. rpm2cpio converts the RPM on standard input or first parameter to a CPIO archive on standard output.
  9. Usage:
  10. rpm2cpio < adjtimex-1.20-2.1.i386.rpm | cpio -it
  11. ./sbin/adjtimex
  12. ./usr/share/doc/adjtimex-1.20
  13. ./usr/share/doc/adjtimex-1.20/COPYING
  14. ./usr/share/doc/adjtimex-1.20/COPYRIGHT
  15. ./usr/share/doc/adjtimex-1.20/README
  16. ./usr/share/man/man8/adjtimex.8.gz
  17. 133 blocks
  18. '''
  19. from __future__ import print_function
  20. import sys
  21. import gzip
  22. import subprocess
  23. try:
  24. from StringIO import StringIO
  25. except ImportError:
  26. from io import StringIO
  27. HAS_LZMA_MODULE = True
  28. try:
  29. import lzma
  30. except ImportError:
  31. try:
  32. import backports.lzma as lzma
  33. except ImportError:
  34. HAS_LZMA_MODULE = False
  35. RPM_MAGIC = b'\xed\xab\xee\xdb'
  36. GZIP_MAGIC = b'\x1f\x8b'
  37. XZ_MAGIC = b'\xfd7zXZ\x00'
  38. def gzip_decompress(data):
  39. gzstream = StringIO(data)
  40. gzipper = gzip.GzipFile(fileobj=gzstream)
  41. data = gzipper.read()
  42. return data
  43. def xz_decompress(data):
  44. if HAS_LZMA_MODULE:
  45. return lzma.decompress(data)
  46. unxz = subprocess.Popen(['unxz'],
  47. stdin=subprocess.PIPE,
  48. stdout=subprocess.PIPE)
  49. data = unxz.communicate(input=data)[0]
  50. return data
  51. def is_rpm(reader):
  52. lead = reader.read(96)
  53. return lead[0:4] == RPM_MAGIC
  54. def extract_cpio(reader):
  55. data = reader.read()
  56. decompress = None
  57. idx = data.find(XZ_MAGIC)
  58. if idx != -1:
  59. decompress = xz_decompress
  60. pos = idx
  61. idx = data.find(GZIP_MAGIC)
  62. if idx != -1 and decompress is None:
  63. decompress = gzip_decompress
  64. pos = idx
  65. if decompress is None:
  66. return None
  67. data = decompress(data[pos:])
  68. return data
  69. def rpm2cpio(stream_in=None, stream_out=None):
  70. if stream_in is None:
  71. stream_in = sys.stdin
  72. if stream_out is None:
  73. stream_out = sys.stdout
  74. try:
  75. reader = stream_in.buffer
  76. writer = stream_out.buffer
  77. except AttributeError:
  78. reader = stream_in
  79. writer = stream_out
  80. if not is_rpm(reader):
  81. raise IOError('the input is not a RPM package')
  82. cpio = extract_cpio(reader)
  83. if cpio is None:
  84. raise IOError('could not find compressed cpio archive')
  85. writer.write(cpio)
  86. def main(args=None):
  87. if args is None:
  88. args = sys.argv
  89. if args[1:]:
  90. try:
  91. fin = open(args[1])
  92. rpm2cpio(fin)
  93. fin.close()
  94. except IOError as e:
  95. print('Error:', args[1], e)
  96. sys.exit(1)
  97. except OSError as e:
  98. print('Error: could not find lzma extractor')
  99. print("Please, install Python's lzma module or the xz utility")
  100. sys.exit(1)
  101. else:
  102. try:
  103. rpm2cpio()
  104. except IOError as e:
  105. print('Error:', e)
  106. sys.exit(1)
  107. except OSError as e:
  108. print('Error: could not find lzma extractor')
  109. print("Please install Python's lzma module or the xz utility")
  110. sys.exit(1)
  111. if __name__ == '__main__':
  112. try:
  113. main()
  114. except KeyboardInterrupt:
  115. print('Interrupted!')