You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gpthybrid 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #!/usr/bin/python -tt
  2. # -*- coding: utf-8 -*-
  3. from subprocess import *
  4. from optparse import OptionParser
  5. parser = OptionParser()
  6. parser.add_option("-l", "--label", dest="l", default="", help="set the partlabel stem for rootfs partitions")
  7. parser.add_option("-i", "--iso", dest="i", help="name of the iso to gpthybridise")
  8. parser.add_option("-s", "--sector", dest="s", default=4, help="size of sectors to use in resulting partition table")
  9. (options, args) = parser.parse_args()
  10. iso_file = options.i
  11. label = options.l
  12. sectors = options.s
  13. def modup(number,mod,target):
  14. if (number % mod != target):
  15. number = number + target - number % mod
  16. return number
  17. def moddown(number,mod,target):
  18. if (number % mod != target):
  19. adjust = number % mod - target
  20. if (adjust > 0):
  21. number -= adjust
  22. else:
  23. number -= mod + adjust
  24. return number
  25. buffout = "gpthybridising iso %s" % iso_file
  26. if len(label):
  27. buffout = "%s with label %s" % (buffout, label)
  28. print buffout
  29. # extract start and end of space to partition from existing gpt
  30. gdisks = Popen(["/sbin/gdisk","-l",iso_file],stdout=PIPE).communicate()[0]
  31. last = 0
  32. end = 0
  33. i = 0
  34. for old_part in gdisks.split("\n"):
  35. if old_part.startswith(' 1'):
  36. # below we want last as "end" of space before 1st partiion
  37. last = int(old_part.split()[1])-1
  38. # min 63 and round up to %sectors==sectors-1 (so 63 means next starts on 64)
  39. if last<63:
  40. last=63
  41. last = modup(last,sectors,sectors-1)
  42. print "first partition set last to %i" % last
  43. if old_part.startswith(' '):
  44. # end should be the last used sector
  45. testend = int(old_part.split()[2])
  46. if (testend > end):
  47. end = modup(testend,sectors,sectors-1)
  48. print "got partition ending: %i" % end
  49. i += 1
  50. # get the lba addresses of the files using osirrox
  51. parts = list()
  52. osirrox=list(["/usr/bin/osirrox", "-pkt_output", "on",
  53. "-indev", iso_file,
  54. '-logfile', '.', '-',])
  55. #'-find', '/efi.img', '-exec', 'report_lba', '--'])
  56. for file in args:
  57. osirrox.extend(['-find', file, '-exec', 'report_lba', '--'])
  58. print "running: %s" % " ".join(osirrox)
  59. for line in check_output(osirrox).split("\n"):
  60. if line[:22] == 'R:1: File data lba: 0':
  61. # extract the fields
  62. (t, s, b, f, n) = line.split(',')
  63. # osirrox talks in 2048b sectors so *4
  64. s = int(s.split()[0])*4
  65. b = int(b.split()[0])*4
  66. # drop the quotes around the name
  67. n = n.split()[0].split("'")[1]
  68. # rebuild list in post in order
  69. done = 0
  70. post = list()
  71. for part in (parts):
  72. if s < int(part.split()[0]):
  73. # we start before this part
  74. if done == 0:
  75. # add ourselves if not done
  76. post.append("%s %s %s" % (moddown(s,sectors,0), modup(s+b-1,sectors,3), n))
  77. done = 1
  78. post.append(part)
  79. if done == 0:
  80. # no parts for us to go before so add to the end
  81. post.append("%s %s %s" % (moddown(s,sectors,0), modup(s+b-1,sectors,3), n))
  82. parts = post
  83. # gdisk commands to delete the existing partitions
  84. cmddel = ""
  85. # all > 1 need the number
  86. while (i>1):
  87. cmddel += """d
  88. %i
  89. """ % i
  90. i -= 1
  91. # the first partition needs no number
  92. if i==1:
  93. cmddel += "d\n"
  94. # gdisk commands to create the partitions
  95. # gap and pnum just count
  96. gap = 1
  97. pnum = 1
  98. # set sectors alignment (2048b iso sector size by default) for partition creation
  99. cmdpart = """x
  100. l
  101. %i
  102. m
  103. """ % sectors
  104. for part in parts:
  105. (s, e, n) = part.split()
  106. # default to ms basic partition and no custom label
  107. t = '0700'
  108. l=''
  109. if len(n) > 4 and ( n[-6:] == '.amd64' or n[-4:] == '.686' or n[-2:] == '.2' ):
  110. t = '8300'
  111. # use label.extension or just the filename as the partlabel
  112. if len(label)==0:
  113. l = '%s' % n
  114. else:
  115. l = '%s.%s' % (label, n[n.rfind('.')+1:])
  116. elif len(n) > 6 and n[-7:] == 'efi.img':
  117. t = 'ef00'
  118. elif len(n) >5 and n[-5:] == '.ef02':
  119. t = 'ef02'
  120. # if the last partition ended more then sectors less then this starts
  121. if int(s)-last >= sectors:
  122. cmdpart += """n
  123. %i
  124. %i
  125. %i
  126. 0700
  127. c
  128. """ % (pnum, modup(last+1,sectors,0), moddown(int(s)-1,sectors,3))
  129. if pnum > 1:
  130. cmdpart += "%s\n" % str(pnum)
  131. cmdpart += "Gap%i\n" % (gap)
  132. pnum += 1
  133. gap += 1
  134. # create the partition itself
  135. cmdpart += """n
  136. %i
  137. %s
  138. %s
  139. %s
  140. """ % (pnum, s, e, t)
  141. if len(l) > 0:
  142. cmdpart += """c
  143. %i
  144. %s
  145. """ % (pnum, l)
  146. pnum += 1
  147. last = int(e)
  148. cmdpart += """p
  149. """
  150. # create a gap from end of last partition and end of last gap if needed
  151. if (end-last>sectors-1):
  152. cmdpart += """n
  153. %i
  154. %s
  155. 0700
  156. c
  157. %i
  158. Gap%i
  159. p
  160. """ % (pnum,modup(last+1,sectors,0), pnum, gap)
  161. # set back to normal 2048 sector alignment for new partitions
  162. cmdpart += """x
  163. l
  164. 2048
  165. m
  166. """
  167. # confirm writing the partition table
  168. cmdend = """w
  169. Y
  170. """
  171. # run our commands through gdisk
  172. cmd = "%s\n%s\n%s" % (cmddel, cmdpart, cmdend)
  173. print "gdisk stdin: %s" % cmd.replace("\n", "\\n")
  174. gdisks = Popen(["/sbin/gdisk",iso_file],stdin=PIPE).communicate(input=cmd)
  175. # TODO read gdisk result and verify or throw big warning/error