34 |
34 |
import os
|
35 |
35 |
import re
|
36 |
36 |
import tempfile
|
|
37 |
import uuid
|
37 |
38 |
from collections import namedtuple
|
38 |
39 |
|
39 |
40 |
import parted
|
... | ... | |
43 |
44 |
from image_creator.util import FatalError
|
44 |
45 |
from image_creator.util import try_fail_repeat
|
45 |
46 |
from image_creator.util import free_space
|
|
47 |
from image_creator.gpt import GPTPartitionTable
|
46 |
48 |
|
47 |
49 |
findfs = get_command('findfs')
|
48 |
50 |
dd = get_command('dd')
|
... | ... | |
128 |
130 |
|
129 |
131 |
def _create_partition_table(self, image):
|
130 |
132 |
|
131 |
|
if self.disk.type != 'msdos':
|
132 |
|
raise FatalError('Only msdos partition tables are supported')
|
133 |
|
|
134 |
133 |
# Copy the MBR and the space between the MBR and the first partition.
|
135 |
|
# In Grub version 1 Stage 1.5 is located there.
|
|
134 |
# In msdos partitons tables Grub Stage 1.5 is located there.
|
|
135 |
# In gpt partition tables the Primary GPT Header is there.
|
136 |
136 |
first_sector = self.disk.getPrimaryPartitions()[0].geometry.start
|
137 |
137 |
|
138 |
138 |
dd('if=%s' % self.disk.device.path, 'of=%s' % image,
|
139 |
139 |
'bs=%d' % self.disk.device.sectorSize,
|
140 |
140 |
'count=%d' % first_sector, 'conv=notrunc')
|
141 |
141 |
|
|
142 |
if self.disk.type == 'gpt':
|
|
143 |
# Copy the Secondary GPT Header
|
|
144 |
table = GPTPartitionTable(self.disk.device.path)
|
|
145 |
dd('if=%s' % self.disk.device.path, 'of=%s' % image,
|
|
146 |
'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc',
|
|
147 |
'seek=%d' % table.primary.last_usable_lba,
|
|
148 |
'skip=%d' % table.primary.last_usable_lba)
|
|
149 |
|
142 |
150 |
# Create the Extended boot records (EBRs) in the image
|
143 |
151 |
extended = self.disk.getExtendedPartition()
|
144 |
152 |
if not extended:
|
... | ... | |
172 |
180 |
|
173 |
181 |
new_end = self.disk.device.length
|
174 |
182 |
|
175 |
|
image_dev = parted.Device(image)
|
176 |
|
image_disk = parted.Disk(image_dev)
|
|
183 |
image_disk = parted.Disk(parted.Device(image))
|
177 |
184 |
|
178 |
185 |
is_extended = lambda p: p.type == parted.PARTITION_EXTENDED
|
179 |
186 |
is_logical = lambda p: p.type == parted.PARTITION_LOGICAL
|
... | ... | |
188 |
195 |
|
189 |
196 |
image_disk.deletePartition(
|
190 |
197 |
image_disk.getPartitionBySector(last.start))
|
191 |
|
image_disk.commit()
|
|
198 |
image_disk.commitToDevice()
|
192 |
199 |
|
193 |
200 |
if is_logical(last) and last.num == 5:
|
194 |
201 |
extended = image_disk.getExtendedPartition()
|
195 |
202 |
image_disk.deletePartition(extended)
|
196 |
|
image_disk.commit()
|
|
203 |
image_disk.commitToDevice()
|
197 |
204 |
partitions.remove(filter(is_extended, partitions)[0])
|
198 |
205 |
|
199 |
206 |
partitions.remove(last)
|
200 |
207 |
last = partitions[-1]
|
201 |
208 |
|
202 |
|
# Leave 2048 blocks at the end
|
203 |
|
new_end = last.end + 2048
|
|
209 |
new_end = last.end
|
204 |
210 |
|
205 |
211 |
mount_options = self._get_mount_options(
|
206 |
212 |
self.disk.getPartitionBySector(last.start).path)
|
... | ... | |
220 |
226 |
image_disk.getPartitionBySector(last.start),
|
221 |
227 |
parted.Constraint(device=image_disk.device),
|
222 |
228 |
start=last.start, end=part_end)
|
223 |
|
image_disk.commit()
|
|
229 |
image_disk.commitToDevice()
|
224 |
230 |
|
225 |
231 |
# Parted may have changed this for better alignment
|
226 |
232 |
part_end = image_disk.getPartitionBySector(last.start).geometry.end
|
227 |
233 |
last = last._replace(end=part_end)
|
228 |
234 |
partitions[-1] = last
|
229 |
235 |
|
230 |
|
# Leave 2048 blocks at the end.
|
231 |
|
new_end = part_end + 2048
|
|
236 |
new_end = part_end
|
232 |
237 |
|
233 |
238 |
if last.type == parted.PARTITION_LOGICAL:
|
234 |
239 |
# Fix the extended partition
|
235 |
|
extended = disk.getExtendedPartition()
|
236 |
|
|
237 |
|
image_disk.setPartitionGeometry(
|
238 |
|
extended, parted.Constraint(device=img_dev),
|
239 |
|
ext.geometry.start, end=last.end)
|
240 |
|
image_disk.commit()
|
|
240 |
image_disk.minimizeExtendedPartition()
|
241 |
241 |
|
242 |
|
# image_dev.destroy()
|
243 |
|
return new_end
|
|
242 |
return (new_end, self._get_partitions(image_disk))
|
244 |
243 |
|
245 |
244 |
def _map_partition(self, dev, num, start, end):
|
246 |
|
name = os.path.basename(dev)
|
|
245 |
name = os.path.basename(dev) + "_" + uuid.uuid4().hex
|
247 |
246 |
tablefd, table = tempfile.mkstemp()
|
248 |
247 |
try:
|
249 |
248 |
size = end - start + 1
|
... | ... | |
321 |
320 |
'/boot/grub/menu.lst',
|
322 |
321 |
'/boot/grub/grub.conf']
|
323 |
322 |
|
324 |
|
orig = dict(map(
|
325 |
|
lambda p: (
|
326 |
|
p.number,
|
327 |
|
blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip()),
|
328 |
|
self.disk.partitions))
|
|
323 |
orig = {}
|
|
324 |
for p in self.disk.partitions:
|
|
325 |
if p.number in new_uuid.keys():
|
|
326 |
orig[p.number] = \
|
|
327 |
blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip()
|
329 |
328 |
|
330 |
329 |
for f in map(lambda f: target + f, files):
|
331 |
|
|
332 |
330 |
if not os.path.exists(f):
|
333 |
331 |
continue
|
334 |
332 |
|
... | ... | |
340 |
338 |
line = re.sub(orig[i], uuid, line)
|
341 |
339 |
dest.write(line)
|
342 |
340 |
|
343 |
|
def _create_filesystems(self, image):
|
|
341 |
def _create_filesystems(self, image, partitions):
|
344 |
342 |
|
345 |
343 |
filesystem = {}
|
346 |
344 |
for p in self.disk.partitions:
|
347 |
345 |
filesystem[p.number] = self._get_mount_options(p.path)
|
348 |
346 |
|
349 |
|
partitions = self._get_partitions(parted.Disk(parted.Device(image)))
|
350 |
347 |
unmounted = filter(lambda p: filesystem[p.num] is None, partitions)
|
351 |
348 |
mounted = filter(lambda p: filesystem[p.num] is not None, partitions)
|
352 |
349 |
|
... | ... | |
429 |
426 |
os.close(fd)
|
430 |
427 |
|
431 |
428 |
self._create_partition_table(image)
|
432 |
|
|
433 |
|
end_sector = self._shrink_partitions(image)
|
434 |
|
|
435 |
|
size = (end_sector + 1) * self.disk.device.sectorSize
|
|
429 |
end_sector, partitions = self._shrink_partitions(image)
|
|
430 |
|
|
431 |
if self.disk.type == 'gpt':
|
|
432 |
old_size = size
|
|
433 |
size = (end_sector + 1) * self.disk.device.sectorSize
|
|
434 |
ptable = GPTPartitionTable(image)
|
|
435 |
size = ptable.shrink(size, old_size)
|
|
436 |
else:
|
|
437 |
# Alighn to 2048
|
|
438 |
end_sector = ((end_sector + 2047) // 2048) * 2048
|
|
439 |
size = (end_sector + 1) * self.disk.device.sectorSize
|
436 |
440 |
|
437 |
441 |
# Truncate image to the new size.
|
438 |
442 |
fd = os.open(image, os.O_RDWR)
|
... | ... | |
449 |
453 |
dirname)
|
450 |
454 |
self.out.success("sufficient")
|
451 |
455 |
|
452 |
|
self._create_filesystems(image)
|
|
456 |
self._create_filesystems(image, partitions)
|
453 |
457 |
|
454 |
458 |
return image
|
455 |
459 |
|