Commit b0376b3f authored by Nikos Skalkotos's avatar Nikos Skalkotos

Add support for gpt partitions in bundle_volume

parent aaacdc1f
......@@ -34,6 +34,7 @@
import os
import re
import tempfile
import uuid
from collections import namedtuple
import parted
......@@ -43,6 +44,7 @@ from image_creator.util import get_command
from image_creator.util import FatalError
from image_creator.util import try_fail_repeat
from image_creator.util import free_space
from image_creator.gpt import GPTPartitionTable
findfs = get_command('findfs')
dd = get_command('dd')
......@@ -128,17 +130,23 @@ class BundleVolume(object):
def _create_partition_table(self, image):
if self.disk.type != 'msdos':
raise FatalError('Only msdos partition tables are supported')
# Copy the MBR and the space between the MBR and the first partition.
# In Grub version 1 Stage 1.5 is located there.
# In msdos partitons tables Grub Stage 1.5 is located there.
# In gpt partition tables the Primary GPT Header is there.
first_sector = self.disk.getPrimaryPartitions()[0].geometry.start
dd('if=%s' % self.disk.device.path, 'of=%s' % image,
'bs=%d' % self.disk.device.sectorSize,
'count=%d' % first_sector, 'conv=notrunc')
if self.disk.type == 'gpt':
# Copy the Secondary GPT Header
table = GPTPartitionTable(self.disk.device.path)
dd('if=%s' % self.disk.device.path, 'of=%s' % image,
'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc',
'seek=%d' % table.primary.last_usable_lba,
'skip=%d' % table.primary.last_usable_lba)
# Create the Extended boot records (EBRs) in the image
extended = self.disk.getExtendedPartition()
if not extended:
......@@ -172,8 +180,7 @@ class BundleVolume(object):
new_end = self.disk.device.length
image_dev = parted.Device(image)
image_disk = parted.Disk(image_dev)
image_disk = parted.Disk(parted.Device(image))
is_extended = lambda p: p.type == parted.PARTITION_EXTENDED
is_logical = lambda p: p.type == parted.PARTITION_LOGICAL
......@@ -188,19 +195,18 @@ class BundleVolume(object):
image_disk.deletePartition(
image_disk.getPartitionBySector(last.start))
image_disk.commit()
image_disk.commitToDevice()
if is_logical(last) and last.num == 5:
extended = image_disk.getExtendedPartition()
image_disk.deletePartition(extended)
image_disk.commit()
image_disk.commitToDevice()
partitions.remove(filter(is_extended, partitions)[0])
partitions.remove(last)
last = partitions[-1]
# Leave 2048 blocks at the end
new_end = last.end + 2048
new_end = last.end
mount_options = self._get_mount_options(
self.disk.getPartitionBySector(last.start).path)
......@@ -220,30 +226,23 @@ class BundleVolume(object):
image_disk.getPartitionBySector(last.start),
parted.Constraint(device=image_disk.device),
start=last.start, end=part_end)
image_disk.commit()
image_disk.commitToDevice()
# Parted may have changed this for better alignment
part_end = image_disk.getPartitionBySector(last.start).geometry.end
last = last._replace(end=part_end)
partitions[-1] = last
# Leave 2048 blocks at the end.
new_end = part_end + 2048
new_end = part_end
if last.type == parted.PARTITION_LOGICAL:
# Fix the extended partition
extended = disk.getExtendedPartition()
image_disk.setPartitionGeometry(
extended, parted.Constraint(device=img_dev),
ext.geometry.start, end=last.end)
image_disk.commit()
image_disk.minimizeExtendedPartition()
# image_dev.destroy()
return new_end
return (new_end, self._get_partitions(image_disk))
def _map_partition(self, dev, num, start, end):
name = os.path.basename(dev)
name = os.path.basename(dev) + "_" + uuid.uuid4().hex
tablefd, table = tempfile.mkstemp()
try:
size = end - start + 1
......@@ -321,14 +320,13 @@ class BundleVolume(object):
'/boot/grub/menu.lst',
'/boot/grub/grub.conf']
orig = dict(map(
lambda p: (
p.number,
blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip()),
self.disk.partitions))
orig = {}
for p in self.disk.partitions:
if p.number in new_uuid.keys():
orig[p.number] = \
blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip()
for f in map(lambda f: target + f, files):
if not os.path.exists(f):
continue
......@@ -340,13 +338,12 @@ class BundleVolume(object):
line = re.sub(orig[i], uuid, line)
dest.write(line)
def _create_filesystems(self, image):
def _create_filesystems(self, image, partitions):
filesystem = {}
for p in self.disk.partitions:
filesystem[p.number] = self._get_mount_options(p.path)
partitions = self._get_partitions(parted.Disk(parted.Device(image)))
unmounted = filter(lambda p: filesystem[p.num] is None, partitions)
mounted = filter(lambda p: filesystem[p.num] is not None, partitions)
......@@ -429,10 +426,17 @@ class BundleVolume(object):
os.close(fd)
self._create_partition_table(image)
end_sector = self._shrink_partitions(image)
size = (end_sector + 1) * self.disk.device.sectorSize
end_sector, partitions = self._shrink_partitions(image)
if self.disk.type == 'gpt':
old_size = size
size = (end_sector + 1) * self.disk.device.sectorSize
ptable = GPTPartitionTable(image)
size = ptable.shrink(size, old_size)
else:
# Alighn to 2048
end_sector = ((end_sector + 2047) // 2048) * 2048
size = (end_sector + 1) * self.disk.device.sectorSize
# Truncate image to the new size.
fd = os.open(image, os.O_RDWR)
......@@ -449,7 +453,7 @@ class BundleVolume(object):
dirname)
self.out.success("sufficient")
self._create_filesystems(image)
self._create_filesystems(image, partitions)
return image
......
......@@ -296,6 +296,7 @@ class GPTPartitionTable(object):
d.write(self.mbr.pack())
d.write(self.primary.pack())
d.write('\x00' * (BLOCKSIZE - self.primary.size()))
d.write(self.part_entries)
d.seek(self.secondary.part_entry_start * BLOCKSIZE)
d.write(self.part_entries)
d.seek(self.primary.backup_lba * BLOCKSIZE)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment