mirror of
https://git.yoctoproject.org/poky
synced 2026-03-19 13:49:41 +01:00
wic: Remove gpt_parser
wic doesn't currently use it, so remove. (From OE-Core rev: d3a490d5421405bf9e002c6c65ffb831ea6b767e) Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
5a8bcfb562
commit
946dbec4eb
@@ -78,9 +78,7 @@ class BootimgEFIPlugin(SourcePlugin):
|
||||
if cr._ptable_format == 'msdos':
|
||||
rootstr = rootdev
|
||||
else:
|
||||
if not root_part_uuid:
|
||||
raise MountError("Cannot find the root GPT partition UUID")
|
||||
rootstr = "PARTUUID=%s" % root_part_uuid
|
||||
raise MountError("Unsupported partition table format found")
|
||||
|
||||
grubefi_conf += "linux %s root=%s rootwait %s\n" \
|
||||
% (kernel, rootstr, options)
|
||||
|
||||
@@ -50,9 +50,7 @@ class BootimgPcbiosPlugin(SourcePlugin):
|
||||
disk image. In this case, we install the MBR.
|
||||
"""
|
||||
mbrfile = "%s/syslinux/" % bootimg_dir
|
||||
if cr._ptable_format == 'gpt':
|
||||
mbrfile += "gptmbr.bin"
|
||||
else:
|
||||
if cr._ptable_format == 'msdos':
|
||||
mbrfile += "mbr.bin"
|
||||
|
||||
if not os.path.exists(mbrfile):
|
||||
@@ -110,9 +108,7 @@ class BootimgPcbiosPlugin(SourcePlugin):
|
||||
if cr._ptable_format == 'msdos':
|
||||
rootstr = rootdev
|
||||
else:
|
||||
if not root_part_uuid:
|
||||
raise MountError("Cannot find the root GPT partition UUID")
|
||||
rootstr = "PARTUUID=%s" % root_part_uuid
|
||||
raise MountError("Unsupported partition table format found")
|
||||
|
||||
syslinux_conf += "APPEND label=boot root=%s %s\n" % (rootstr, options)
|
||||
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
#!/usr/bin/python -tt
|
||||
#
|
||||
# Copyright (c) 2013 Intel, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; version 2 of the License
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
""" This module implements a simple GPT partitions parser which can read the
|
||||
GPT header and the GPT partition table. """
|
||||
|
||||
import struct
|
||||
import uuid
|
||||
import binascii
|
||||
from mic.utils.errors import MountError
|
||||
|
||||
_GPT_HEADER_FORMAT = "<8s4sIIIQQQQ16sQIII"
|
||||
_GPT_HEADER_SIZE = struct.calcsize(_GPT_HEADER_FORMAT)
|
||||
_GPT_ENTRY_FORMAT = "<16s16sQQQ72s"
|
||||
_GPT_ENTRY_SIZE = struct.calcsize(_GPT_ENTRY_FORMAT)
|
||||
_SUPPORTED_GPT_REVISION = '\x00\x00\x01\x00'
|
||||
|
||||
def _stringify_uuid(binary_uuid):
|
||||
""" A small helper function to transform a binary UUID into a string
|
||||
format. """
|
||||
|
||||
uuid_str = str(uuid.UUID(bytes_le = binary_uuid))
|
||||
|
||||
return uuid_str.upper()
|
||||
|
||||
def _calc_header_crc(raw_hdr):
|
||||
""" Calculate GPT header CRC32 checksum. The 'raw_hdr' parameter has to
|
||||
be a list or a tuple containing all the elements of the GPT header in a
|
||||
"raw" form, meaning that it should simply contain "unpacked" disk data.
|
||||
"""
|
||||
|
||||
raw_hdr = list(raw_hdr)
|
||||
raw_hdr[3] = 0
|
||||
raw_hdr = struct.pack(_GPT_HEADER_FORMAT, *raw_hdr)
|
||||
|
||||
return binascii.crc32(raw_hdr) & 0xFFFFFFFF
|
||||
|
||||
def _validate_header(raw_hdr):
|
||||
""" Validate the GPT header. The 'raw_hdr' parameter has to be a list or a
|
||||
tuple containing all the elements of the GPT header in a "raw" form,
|
||||
meaning that it should simply contain "unpacked" disk data. """
|
||||
|
||||
# Validate the signature
|
||||
if raw_hdr[0] != 'EFI PART':
|
||||
raise MountError("GPT partition table not found")
|
||||
|
||||
# Validate the revision
|
||||
if raw_hdr[1] != _SUPPORTED_GPT_REVISION:
|
||||
raise MountError("Unsupported GPT revision '%s', supported revision " \
|
||||
"is '%s'" % \
|
||||
(binascii.hexlify(raw_hdr[1]),
|
||||
binascii.hexlify(_SUPPORTED_GPT_REVISION)))
|
||||
|
||||
# Validate header size
|
||||
if raw_hdr[2] != _GPT_HEADER_SIZE:
|
||||
raise MountError("Bad GPT header size: %d bytes, expected %d" % \
|
||||
(raw_hdr[2], _GPT_HEADER_SIZE))
|
||||
|
||||
crc = _calc_header_crc(raw_hdr)
|
||||
if raw_hdr[3] != crc:
|
||||
raise MountError("GPT header crc mismatch: %#x, should be %#x" % \
|
||||
(crc, raw_hdr[3]))
|
||||
|
||||
class GptParser:
|
||||
""" GPT partition table parser. Allows reading the GPT header and the
|
||||
partition table, as well as modifying the partition table records. """
|
||||
|
||||
def __init__(self, disk_path, sector_size = 512):
|
||||
""" The class constructor which accepts the following parameters:
|
||||
* disk_path - full path to the disk image or device node
|
||||
* sector_size - size of a disk sector in bytes """
|
||||
|
||||
self.sector_size = sector_size
|
||||
self.disk_path = disk_path
|
||||
|
||||
try:
|
||||
self._disk_obj = open(disk_path, 'r+b')
|
||||
except IOError as err:
|
||||
raise MountError("Cannot open file '%s' for reading GPT " \
|
||||
"partitions: %s" % (disk_path, err))
|
||||
|
||||
def __del__(self):
|
||||
""" The class destructor. """
|
||||
|
||||
self._disk_obj.close()
|
||||
|
||||
def _read_disk(self, offset, size):
|
||||
""" A helper function which reads 'size' bytes from offset 'offset' of
|
||||
the disk and checks all the error conditions. """
|
||||
|
||||
self._disk_obj.seek(offset)
|
||||
try:
|
||||
data = self._disk_obj.read(size)
|
||||
except IOError as err:
|
||||
raise MountError("cannot read from '%s': %s" % \
|
||||
(self.disk_path, err))
|
||||
|
||||
if len(data) != size:
|
||||
raise MountError("cannot read %d bytes from offset '%d' of '%s', " \
|
||||
"read only %d bytes" % \
|
||||
(size, offset, self.disk_path, len(data)))
|
||||
|
||||
return data
|
||||
|
||||
def _write_disk(self, offset, buf):
|
||||
""" A helper function which writes buffer 'buf' to offset 'offset' of
|
||||
the disk. This function takes care of unaligned writes and checks all
|
||||
the error conditions. """
|
||||
|
||||
# Since we may be dealing with a block device, we only can write in
|
||||
# 'self.sector_size' chunks. Find the aligned starting and ending
|
||||
# disk offsets to read.
|
||||
start = (offset / self.sector_size) * self.sector_size
|
||||
end = ((start + len(buf)) / self.sector_size + 1) * self.sector_size
|
||||
|
||||
data = self._read_disk(start, end - start)
|
||||
off = offset - start
|
||||
data = data[:off] + buf + data[off + len(buf):]
|
||||
|
||||
self._disk_obj.seek(start)
|
||||
try:
|
||||
self._disk_obj.write(data)
|
||||
except IOError as err:
|
||||
raise MountError("cannot write to '%s': %s" % (self.disk_path, err))
|
||||
|
||||
def read_header(self, primary = True):
|
||||
""" Read and verify the GPT header and return a dictionary containing
|
||||
the following elements:
|
||||
|
||||
'signature' : header signature
|
||||
'revision' : header revision
|
||||
'hdr_size' : header size in bytes
|
||||
'hdr_crc' : header CRC32
|
||||
'hdr_lba' : LBA of this header
|
||||
'hdr_offs' : byte disk offset of this header
|
||||
'backup_lba' : backup header LBA
|
||||
'backup_offs' : byte disk offset of backup header
|
||||
'first_lba' : first usable LBA for partitions
|
||||
'first_offs' : first usable byte disk offset for partitions
|
||||
'last_lba' : last usable LBA for partitions
|
||||
'last_offs' : last usable byte disk offset for partitions
|
||||
'disk_uuid' : UUID of the disk
|
||||
'ptable_lba' : starting LBA of array of partition entries
|
||||
'ptable_offs' : disk byte offset of the start of the partition table
|
||||
'ptable_size' : partition table size in bytes
|
||||
'entries_cnt' : number of available partition table entries
|
||||
'entry_size' : size of a single partition entry
|
||||
'ptable_crc' : CRC32 of the partition table
|
||||
'primary' : a boolean, if 'True', this is the primary GPT header,
|
||||
if 'False' - the secondary
|
||||
'primary_str' : contains string "primary" if this is the primary GPT
|
||||
header, and "backup" otherwise
|
||||
|
||||
This dictionary corresponds to the GPT header format. Please, see the
|
||||
UEFI standard for the description of these fields.
|
||||
|
||||
If the 'primary' parameter is 'True', the primary GPT header is read,
|
||||
otherwise the backup GPT header is read instead. """
|
||||
|
||||
# Read and validate the primary GPT header
|
||||
raw_hdr = self._read_disk(self.sector_size, _GPT_HEADER_SIZE)
|
||||
raw_hdr = struct.unpack(_GPT_HEADER_FORMAT, raw_hdr)
|
||||
_validate_header(raw_hdr)
|
||||
primary_str = "primary"
|
||||
|
||||
if not primary:
|
||||
# Read and validate the backup GPT header
|
||||
raw_hdr = self._read_disk(raw_hdr[6] * self.sector_size, _GPT_HEADER_SIZE)
|
||||
raw_hdr = struct.unpack(_GPT_HEADER_FORMAT, raw_hdr)
|
||||
_validate_header(raw_hdr)
|
||||
primary_str = "backup"
|
||||
|
||||
return { 'signature' : raw_hdr[0],
|
||||
'revision' : raw_hdr[1],
|
||||
'hdr_size' : raw_hdr[2],
|
||||
'hdr_crc' : raw_hdr[3],
|
||||
'hdr_lba' : raw_hdr[5],
|
||||
'hdr_offs' : raw_hdr[5] * self.sector_size,
|
||||
'backup_lba' : raw_hdr[6],
|
||||
'backup_offs' : raw_hdr[6] * self.sector_size,
|
||||
'first_lba' : raw_hdr[7],
|
||||
'first_offs' : raw_hdr[7] * self.sector_size,
|
||||
'last_lba' : raw_hdr[8],
|
||||
'last_offs' : raw_hdr[8] * self.sector_size,
|
||||
'disk_uuid' :_stringify_uuid(raw_hdr[9]),
|
||||
'ptable_lba' : raw_hdr[10],
|
||||
'ptable_offs' : raw_hdr[10] * self.sector_size,
|
||||
'ptable_size' : raw_hdr[11] * raw_hdr[12],
|
||||
'entries_cnt' : raw_hdr[11],
|
||||
'entry_size' : raw_hdr[12],
|
||||
'ptable_crc' : raw_hdr[13],
|
||||
'primary' : primary,
|
||||
'primary_str' : primary_str }
|
||||
|
||||
def _read_raw_ptable(self, header):
|
||||
""" Read and validate primary or backup partition table. The 'header'
|
||||
argument is the GPT header. If it is the primary GPT header, then the
|
||||
primary partition table is read and validated, otherwise - the backup
|
||||
one. The 'header' argument is a dictionary which is returned by the
|
||||
'read_header()' method. """
|
||||
|
||||
raw_ptable = self._read_disk(header['ptable_offs'],
|
||||
header['ptable_size'])
|
||||
|
||||
crc = binascii.crc32(raw_ptable) & 0xFFFFFFFF
|
||||
if crc != header['ptable_crc']:
|
||||
raise MountError("Partition table at LBA %d (%s) is corrupted" % \
|
||||
(header['ptable_lba'], header['primary_str']))
|
||||
|
||||
return raw_ptable
|
||||
|
||||
def get_partitions(self, primary = True):
|
||||
""" This is a generator which parses the GPT partition table and
|
||||
generates the following dictionary for each partition:
|
||||
|
||||
'index' : the index of the partition table endry
|
||||
'offs' : byte disk offset of the partition table entry
|
||||
'type_uuid' : partition type UUID
|
||||
'part_uuid' : partition UUID
|
||||
'first_lba' : the first LBA
|
||||
'last_lba' : the last LBA
|
||||
'flags' : attribute flags
|
||||
'name' : partition name
|
||||
'primary' : a boolean, if 'True', this is the primary partition
|
||||
table, if 'False' - the secondary
|
||||
'primary_str' : contains string "primary" if this is the primary GPT
|
||||
header, and "backup" otherwise
|
||||
|
||||
This dictionary corresponds to the GPT header format. Please, see the
|
||||
UEFI standard for the description of these fields.
|
||||
|
||||
If the 'primary' parameter is 'True', partitions from the primary GPT
|
||||
partition table are generated, otherwise partitions from the backup GPT
|
||||
partition table are generated. """
|
||||
|
||||
if primary:
|
||||
primary_str = "primary"
|
||||
else:
|
||||
primary_str = "backup"
|
||||
|
||||
header = self.read_header(primary)
|
||||
raw_ptable = self._read_raw_ptable(header)
|
||||
|
||||
for index in xrange(0, header['entries_cnt']):
|
||||
start = header['entry_size'] * index
|
||||
end = start + header['entry_size']
|
||||
raw_entry = struct.unpack(_GPT_ENTRY_FORMAT, raw_ptable[start:end])
|
||||
|
||||
if raw_entry[2] == 0 or raw_entry[3] == 0:
|
||||
continue
|
||||
|
||||
part_name = str(raw_entry[5].decode('UTF-16').split('\0', 1)[0])
|
||||
|
||||
yield { 'index' : index,
|
||||
'offs' : header['ptable_offs'] + start,
|
||||
'type_uuid' : _stringify_uuid(raw_entry[0]),
|
||||
'part_uuid' : _stringify_uuid(raw_entry[1]),
|
||||
'first_lba' : raw_entry[2],
|
||||
'last_lba' : raw_entry[3],
|
||||
'flags' : raw_entry[4],
|
||||
'name' : part_name,
|
||||
'primary' : primary,
|
||||
'primary_str' : primary_str }
|
||||
|
||||
def _change_partition(self, header, entry):
|
||||
""" A helper function for 'change_partitions()' which changes a
|
||||
a paricular instance of the partition table (primary or backup). """
|
||||
|
||||
if entry['index'] >= header['entries_cnt']:
|
||||
raise MountError("Partition table at LBA %d has only %d " \
|
||||
"records cannot change record number %d" % \
|
||||
(header['entries_cnt'], entry['index']))
|
||||
# Read raw GPT header
|
||||
raw_hdr = self._read_disk(header['hdr_offs'], _GPT_HEADER_SIZE)
|
||||
raw_hdr = list(struct.unpack(_GPT_HEADER_FORMAT, raw_hdr))
|
||||
_validate_header(raw_hdr)
|
||||
|
||||
# Prepare the new partition table entry
|
||||
raw_entry = struct.pack(_GPT_ENTRY_FORMAT,
|
||||
uuid.UUID(entry['type_uuid']).bytes_le,
|
||||
uuid.UUID(entry['part_uuid']).bytes_le,
|
||||
entry['first_lba'],
|
||||
entry['last_lba'],
|
||||
entry['flags'],
|
||||
entry['name'].encode('UTF-16'))
|
||||
|
||||
# Write the updated entry to the disk
|
||||
entry_offs = header['ptable_offs'] + \
|
||||
header['entry_size'] * entry['index']
|
||||
self._write_disk(entry_offs, raw_entry)
|
||||
|
||||
# Calculate and update partition table CRC32
|
||||
raw_ptable = self._read_disk(header['ptable_offs'],
|
||||
header['ptable_size'])
|
||||
raw_hdr[13] = binascii.crc32(raw_ptable) & 0xFFFFFFFF
|
||||
|
||||
# Calculate and update the GPT header CRC
|
||||
raw_hdr[3] = _calc_header_crc(raw_hdr)
|
||||
|
||||
# Write the updated header to the disk
|
||||
raw_hdr = struct.pack(_GPT_HEADER_FORMAT, *raw_hdr)
|
||||
self._write_disk(header['hdr_offs'], raw_hdr)
|
||||
|
||||
def change_partition(self, entry):
|
||||
""" Change a GPT partition. The 'entry' argument has the same format as
|
||||
'get_partitions()' returns. This function simply changes the partition
|
||||
table record corresponding to 'entry' in both, the primary and the
|
||||
backup GPT partition tables. The parition table CRC is re-calculated
|
||||
and the GPT headers are modified accordingly. """
|
||||
|
||||
# Change the primary partition table
|
||||
header = self.read_header(True)
|
||||
self._change_partition(header, entry)
|
||||
|
||||
# Change the backup partition table
|
||||
header = self.read_header(False)
|
||||
self._change_partition(header, entry)
|
||||
@@ -24,13 +24,10 @@ from mic import msger
|
||||
from mic.utils import runner
|
||||
from mic.utils.errors import MountError
|
||||
from mic.utils.fs_related import *
|
||||
from mic.utils.gpt_parser import GptParser
|
||||
from mic.utils.oe.misc import *
|
||||
|
||||
# Overhead of the MBR partitioning scheme (just one sector)
|
||||
MBR_OVERHEAD = 1
|
||||
# Overhead of the GPT partitioning scheme
|
||||
GPT_OVERHEAD = 34
|
||||
|
||||
# Size of a sector in bytes
|
||||
SECTOR_SIZE = 512
|
||||
@@ -148,21 +145,20 @@ class PartitionedMount(Mount):
|
||||
'num': None, # Partition number
|
||||
'boot': boot, # Bootable flag
|
||||
'align': align, # Partition alignment
|
||||
'part_type' : part_type, # Partition type
|
||||
'partuuid': None } # Partition UUID (GPT-only)
|
||||
'part_type' : part_type } # Partition type
|
||||
|
||||
self.__add_partition(part)
|
||||
|
||||
def layout_partitions(self, ptable_format = "msdos"):
|
||||
""" 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 either "msdos" or "gpt". """
|
||||
partition table format and may be "msdos". """
|
||||
|
||||
msger.debug("Assigning %s partitions to disks" % ptable_format)
|
||||
|
||||
if ptable_format not in ('msdos', 'gpt'):
|
||||
if ptable_format not in ('msdos'):
|
||||
raise MountError("Unknown partition table format '%s', supported " \
|
||||
"formats are: 'msdos' and 'gpt'" % ptable_format)
|
||||
"formats are: 'msdos'" % ptable_format)
|
||||
|
||||
if self._partitions_layed_out:
|
||||
return
|
||||
@@ -177,12 +173,12 @@ class PartitionedMount(Mount):
|
||||
raise MountError("No disk %s for partition %s" \
|
||||
% (p['disk_name'], p['mountpoint']))
|
||||
|
||||
if p['part_type'] and ptable_format != 'gpt':
|
||||
if p['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.
|
||||
raise MountError("setting custom partition type is only " \
|
||||
"imlemented for GPT partitions")
|
||||
raise MountError("setting custom partition type is not " \
|
||||
"implemented for msdos partitions")
|
||||
|
||||
# Get the disk where the partition is located
|
||||
d = self.disks[p['disk_name']]
|
||||
@@ -192,8 +188,6 @@ class PartitionedMount(Mount):
|
||||
if d['numpart'] == 1:
|
||||
if ptable_format == "msdos":
|
||||
overhead = MBR_OVERHEAD
|
||||
else:
|
||||
overhead = GPT_OVERHEAD
|
||||
|
||||
# Skip one sector required for the partitioning scheme overhead
|
||||
d['offset'] += overhead
|
||||
@@ -250,9 +244,6 @@ class PartitionedMount(Mount):
|
||||
# minumim disk sizes.
|
||||
for disk_name, d in self.disks.items():
|
||||
d['min_size'] = d['offset']
|
||||
if d['ptable_format'] == 'gpt':
|
||||
# Account for the backup partition table at the end of the disk
|
||||
d['min_size'] += GPT_OVERHEAD
|
||||
|
||||
d['min_size'] *= self.sector_size
|
||||
|
||||
@@ -339,10 +330,7 @@ class PartitionedMount(Mount):
|
||||
parted_fs_type, p['start'], p['size'])
|
||||
|
||||
if p['boot']:
|
||||
if d['ptable_format'] == 'gpt':
|
||||
flag_name = "legacy_boot"
|
||||
else:
|
||||
flag_name = "boot"
|
||||
flag_name = "boot"
|
||||
msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \
|
||||
(flag_name, p['num'], d['disk'].device))
|
||||
self.__run_parted(["-s", d['disk'].device, "set",
|
||||
@@ -358,36 +346,6 @@ class PartitionedMount(Mount):
|
||||
self.__run_parted(["-s", d['disk'].device, "set",
|
||||
"%d" % p['num'], "lba", "off"])
|
||||
|
||||
# If the partition table format is "gpt", find out PARTUUIDs for all
|
||||
# the partitions. And if users specified custom parition type UUIDs,
|
||||
# set them.
|
||||
for disk_name, disk in self.disks.items():
|
||||
if disk['ptable_format'] != 'gpt':
|
||||
continue
|
||||
|
||||
pnum = 0
|
||||
gpt_parser = GptParser(d['disk'].device, SECTOR_SIZE)
|
||||
# Iterate over all GPT partitions on this disk
|
||||
for entry in gpt_parser.get_partitions():
|
||||
pnum += 1
|
||||
# Find the matching partition in the 'self.partitions' list
|
||||
for n in d['partitions']:
|
||||
p = self.partitions[n]
|
||||
if p['num'] == pnum:
|
||||
# Found, fetch PARTUUID (partition's unique ID)
|
||||
p['partuuid'] = entry['part_uuid']
|
||||
msger.debug("PARTUUID for partition %d on disk '%s' " \
|
||||
"(mount point '%s') is '%s'" % (pnum, \
|
||||
disk_name, p['mountpoint'], p['partuuid']))
|
||||
if p['part_type']:
|
||||
entry['type_uuid'] = p['part_type']
|
||||
msger.debug("Change type of partition %d on disk " \
|
||||
"'%s' (mount point '%s') to '%s'" % \
|
||||
(pnum, disk_name, p['mountpoint'],
|
||||
p['part_type']))
|
||||
gpt_parser.change_partition(entry)
|
||||
|
||||
del gpt_parser
|
||||
|
||||
def __map_partitions(self):
|
||||
"""Load it if dm_snapshot isn't loaded. """
|
||||
|
||||
Reference in New Issue
Block a user