aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/utils/partitionedfs.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/utils/partitionedfs.py')
-rw-r--r--scripts/lib/wic/utils/partitionedfs.py194
1 files changed, 75 insertions, 119 deletions
diff --git a/scripts/lib/wic/utils/partitionedfs.py b/scripts/lib/wic/utils/partitionedfs.py
index 5397bb704c..cdf8f08015 100644
--- a/scripts/lib/wic/utils/partitionedfs.py
+++ b/scripts/lib/wic/utils/partitionedfs.py
@@ -19,6 +19,7 @@
# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import os
+
from wic import msger
from wic.utils.errors import ImageError
from wic.utils.misc import exec_native_cmd
@@ -33,50 +34,28 @@ GPT_OVERHEAD = 34
# Size of a sector in bytes
SECTOR_SIZE = 512
-class Image():
+class PartitionedImage():
"""
- Generic base object for an image.
-
- An Image is a container for a set of DiskImages and associated
- partitions.
+ Partitioned image in a file.
"""
- def __init__(self, native_sysroot=None):
- self.disks = {}
+
+ def __init__(self, path, ptable_format, native_sysroot=None):
+ self.path = path # Path to the image file
+ self.numpart = 0 # Number of allocated partitions
+ self.realpart = 0 # Number of partitions in the partition table
+ self.offset = 0 # Offset of next partition (in sectors)
+ self.min_size = 0 # Minimum required disk size to fit
+ # all partitions (in bytes)
+ self.ptable_format = ptable_format # Partition table format
+ # Disk system identifier
+ self.identifier = int.from_bytes(os.urandom(4), 'little')
+
self.partitions = []
self.partimages = []
# Size of a sector used in calculations
self.sector_size = SECTOR_SIZE
self.native_sysroot = native_sysroot
- def _add_disk(self, disk_name):
- """ Add a disk 'disk_name' to the internal list of disks. Note,
- 'disk_name' is the name of the disk in the target system
- (e.g., sdb). """
-
- if disk_name in self.disks:
- # We already have this disk
- return
-
- self.disks[disk_name] = \
- {'disk': None, # Disk object
- 'numpart': 0, # Number of allocate partitions
- 'realpart': 0, # Number of partitions in the partition table
- 'partitions': [], # Indexes to self.partitions
- 'offset': 0, # Offset of next partition (in sectors)
- # Minimum required disk size to fit all partitions (in bytes)
- 'min_size': 0,
- 'ptable_format': "msdos", # Partition table format
- 'identifier': None} # Disk system identifier
-
- def add_disk(self, name, disk_obj, identifier):
- """ Add a disk object which have to be partitioned. More than one disk
- can be added. In case of multiple disks, disk partitions have to be
- added for each disk separately with 'add_partition()". """
-
- self._add_disk(name)
- self.disks[name]['disk'] = disk_obj
- self.disks[name]['identifier'] = identifier
-
def add_partition(self, part):
"""
Add the next partition. Partitions have to be added in the
@@ -88,24 +67,19 @@ class Image():
part.size_sec = part.disk_size * 1024 // self.sector_size
self.partitions.append(part)
- self._add_disk(part.disk)
- def layout_partitions(self, ptable_format="msdos"):
+ def layout_partitions(self):
""" Layout the partitions, meaning calculate the position of every
partition on the disk. The 'ptable_format' parameter defines the
partition table format and may be "msdos". """
- msger.debug("Assigning %s partitions to disks" % ptable_format)
+ msger.debug("Assigning %s partitions to disks" % self.ptable_format)
# Go through partitions in the order they are added in .ks file
for num in range(len(self.partitions)):
part = self.partitions[num]
- if part.disk not in self.disks:
- raise ImageError("No disk %s for partition %s" \
- % (part.disk, part.mountpoint))
-
- if ptable_format == 'msdos' and part.part_type:
+ if self.ptable_format == 'msdos' and part.part_type:
# The --part-type can also be implemented for MBR partitions,
# in which case it would map to the 1-byte "partition type"
# filed at offset 3 of the partition entry.
@@ -113,27 +87,24 @@ class Image():
"implemented for msdos partitions")
# Get the disk where the partition is located
- disk = self.disks[part.disk]
- disk['numpart'] += 1
+ self.numpart += 1
if not part.no_table:
- disk['realpart'] += 1
- disk['ptable_format'] = ptable_format
+ self.realpart += 1
- if disk['numpart'] == 1:
- if ptable_format == "msdos":
+ if self.numpart == 1:
+ if self.ptable_format == "msdos":
overhead = MBR_OVERHEAD
- elif ptable_format == "gpt":
+ elif self.ptable_format == "gpt":
overhead = GPT_OVERHEAD
# Skip one sector required for the partitioning scheme overhead
- disk['offset'] += overhead
+ self.offset += overhead
- if disk['realpart'] > 3:
+ if self.realpart > 3:
# Reserve a sector for EBR for every logical partition
# before alignment is performed.
- if ptable_format == "msdos":
- disk['offset'] += 1
-
+ if self.ptable_format == "msdos":
+ self.offset += 1
if part.align:
# If not first partition and we do have alignment set we need
@@ -142,7 +113,7 @@ class Image():
# gaps we could enlargea the previous partition?
# Calc how much the alignment is off.
- align_sectors = disk['offset'] % (part.align * 1024 // self.sector_size)
+ align_sectors = self.offset % (part.align * 1024 // self.sector_size)
if align_sectors:
# If partition is not aligned as required, we need
@@ -151,43 +122,41 @@ class Image():
msger.debug("Realignment for %s%s with %s sectors, original"
" offset %s, target alignment is %sK." %
- (part.disk, disk['numpart'], align_sectors,
- disk['offset'], part.align))
+ (part.disk, self.numpart, align_sectors,
+ self.offset, part.align))
# increase the offset so we actually start the partition on right alignment
- disk['offset'] += align_sectors
+ self.offset += align_sectors
- part.start = disk['offset']
- disk['offset'] += part.size_sec
+ part.start = self.offset
+ self.offset += part.size_sec
part.type = 'primary'
if not part.no_table:
- part.num = disk['realpart']
+ part.num = self.realpart
else:
part.num = 0
- if disk['ptable_format'] == "msdos":
+ if self.ptable_format == "msdos":
# only count the partitions that are in partition table
if len([p for p in self.partitions if not p.no_table]) > 4:
- if disk['realpart'] > 3:
+ if self.realpart > 3:
part.type = 'logical'
- part.num = disk['realpart'] + 1
+ part.num = self.realpart + 1
- disk['partitions'].append(num)
msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d "
"sectors (%d bytes)." \
% (part.mountpoint, part.disk, part.num,
- part.start, disk['offset'] - 1,
+ part.start, self.offset - 1,
part.size_sec, part.size_sec * self.sector_size))
# Once all the partitions have been layed out, we can calculate the
- # minumim disk sizes.
- for disk in self.disks.values():
- disk['min_size'] = disk['offset']
- if disk['ptable_format'] == "gpt":
- disk['min_size'] += GPT_OVERHEAD
+ # minumim disk size
+ self.min_size = self.offset
+ if self.ptable_format == "gpt":
+ self.min_size += GPT_OVERHEAD
- disk['min_size'] *= self.sector_size
+ self.min_size *= self.sector_size
def _create_partition(self, device, parttype, fstype, start, size):
""" Create a partition on an image described by the 'device' object. """
@@ -205,23 +174,18 @@ class Image():
return exec_native_cmd(cmd, self.native_sysroot)
def create(self):
- for dev in self.disks:
- disk = self.disks[dev]
- disk['disk'].create()
-
- for dev in self.disks:
- disk = self.disks[dev]
- msger.debug("Initializing partition table for %s" % \
- (disk['disk'].device))
- exec_native_cmd("parted -s %s mklabel %s" % \
- (disk['disk'].device, disk['ptable_format']),
- self.native_sysroot)
-
- if disk['identifier']:
- msger.debug("Set disk identifier %x" % disk['identifier'])
- with open(disk['disk'].device, 'r+b') as img:
- img.seek(0x1B8)
- img.write(disk['identifier'].to_bytes(4, 'little'))
+ msger.debug("Creating sparse file %s" % self.path)
+ with open(self.path, 'w') as sparse:
+ os.ftruncate(sparse.fileno(), self.min_size)
+
+ msger.debug("Initializing partition table for %s" % self.path)
+ exec_native_cmd("parted -s %s mklabel %s" %
+ (self.path, self.ptable_format), self.native_sysroot)
+
+ msger.debug("Set disk identifier %x" % self.identifier)
+ with open(self.path, 'r+b') as img:
+ img.seek(0x1B8)
+ img.write(self.identifier.to_bytes(4, 'little'))
msger.debug("Creating partitions")
@@ -229,8 +193,7 @@ class Image():
if part.num == 0:
continue
- disk = self.disks[part.disk]
- if disk['ptable_format'] == "msdos" and part.num == 5:
+ if self.ptable_format == "msdos" and part.num == 5:
# Create an extended partition (note: extended
# partition is described in MBR and contains all
# logical partitions). The logical partitions save a
@@ -242,9 +205,9 @@ class Image():
# starts a sector before the first logical partition,
# add a sector at the back, so that there is enough
# room for all logical partitions.
- self._create_partition(disk['disk'].device, "extended",
+ self._create_partition(self.path, "extended",
None, part.start - 1,
- disk['offset'] - part.start + 1)
+ self.offset - part.start + 1)
if part.fstype == "swap":
parted_fs_type = "linux-swap"
@@ -267,7 +230,7 @@ class Image():
part.mountpoint)
part.size_sec -= 1
- self._create_partition(disk['disk'].device, part.type,
+ self._create_partition(self.path, part.type,
parted_fs_type, part.start, part.size_sec)
if part.part_type:
@@ -275,71 +238,64 @@ class Image():
(part.num, part.part_type))
exec_native_cmd("sgdisk --typecode=%d:%s %s" % \
(part.num, part.part_type,
- disk['disk'].device), self.native_sysroot)
+ self.path), self.native_sysroot)
- if part.uuid and disk['ptable_format'] == "gpt":
+ if part.uuid and self.ptable_format == "gpt":
msger.debug("partition %d: set UUID to %s" % \
(part.num, part.uuid))
exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \
- (part.num, part.uuid, disk['disk'].device),
+ (part.num, part.uuid, self.path),
self.native_sysroot)
- if part.label and disk['ptable_format'] == "gpt":
+ if part.label and self.ptable_format == "gpt":
msger.debug("partition %d: set name to %s" % \
(part.num, part.label))
exec_native_cmd("parted -s %s name %d %s" % \
- (disk['disk'].device, part.num, part.label),
+ (self.path, part.num, part.label),
self.native_sysroot)
if part.active:
- flag_name = "legacy_boot" if disk['ptable_format'] == 'gpt' else "boot"
+ flag_name = "legacy_boot" if self.ptable_format == 'gpt' else "boot"
msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \
- (flag_name, part.num, disk['disk'].device))
+ (flag_name, part.num, self.path))
exec_native_cmd("parted -s %s set %d %s on" % \
- (disk['disk'].device, part.num, flag_name),
+ (self.path, part.num, flag_name),
self.native_sysroot)
if part.system_id:
exec_native_cmd("sfdisk --part-type %s %s %s" % \
- (disk['disk'].device, part.num, part.system_id),
+ (self.path, part.num, part.system_id),
self.native_sysroot)
# Parted defaults to enabling the lba flag for fat16 partitions,
# which causes compatibility issues with some firmware (and really
# isn't necessary).
if parted_fs_type == "fat16":
- if disk['ptable_format'] == 'msdos':
+ if self.ptable_format == 'msdos':
msger.debug("Disable 'lba' flag for partition '%s' on disk '%s'" % \
- (part.num, disk['disk'].device))
+ (part.num, self.path))
exec_native_cmd("parted -s %s set %d lba off" % \
- (disk['disk'].device, part.num),
+ (self.path, part.num),
self.native_sysroot)
def cleanup(self):
- if self.disks:
- for dev in self.disks:
- disk = self.disks[dev]
- if hasattr(disk['disk'], 'cleanup'):
- disk['disk'].cleanup()
-
# remove partition images
for image in self.partimages:
- if os.path.isfile(image):
- os.remove(image)
+ os.remove(image)
- def assemble(self, image_file):
+ def assemble(self):
msger.debug("Installing partitions")
for part in self.partitions:
source = part.source_file
if source:
# install source_file contents into a partition
- sparse_copy(source, image_file, part.start * self.sector_size)
+ sparse_copy(source, self.path, part.start * self.sector_size)
msger.debug("Installed %s in partition %d, sectors %d-%d, "
"size %d sectors" % \
(source, part.num, part.start,
part.start + part.size_sec - 1, part.size_sec))
- partimage = image_file + '.p%d' % part.num
+ partimage = self.path + '.p%d' % part.num
os.rename(source, partimage)
self.partimages.append(partimage)