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.
135 lines
5.1 KiB
135 lines
5.1 KiB
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
"""A module to provide interface to gpt information.
|
|
|
|
gpt stands for GUID partition table, it is a data structure describing
|
|
partitions present of a storage device. cgpt is a utility which allows to read
|
|
and modify gpt. This module parses cgpt output to create a dictionary
|
|
including information about all defined partitions including their properties.
|
|
It also allows to modify partition properties as required.
|
|
"""
|
|
|
|
|
|
class CgptError(Exception):
|
|
"""Cgpt-specific exception."""
|
|
pass
|
|
|
|
|
|
class CgptHandler(object):
|
|
"""Object representing one or more gpts present in the system.
|
|
|
|
Attributes:
|
|
os_if: an instance of OSInterface, initialized by the caller.
|
|
devices: a dictionary keyed by the storage device names (as in
|
|
/dev/sda), the contents are dictionaries of cgpt information,
|
|
where keys are partiton names, and contents are in turn
|
|
dictionaries of partition properties, something like the below
|
|
(compressed for brevity):
|
|
{'/dev/sda': {
|
|
'OEM': {'partition': 8, 'Type': 'Linux data', 'UUID': 'xxx'},
|
|
'ROOT-A': {'partition': 3, 'Type': 'ChromeOS rootfs', 'UUID': 'xyz'},
|
|
'ROOT-C': {'partition': 7, 'Type': 'ChromeOS rootfs', 'UUID': 'xzz'},
|
|
'ROOT-B': {'partition': 5, 'Type': 'ChromeOS rootfs', 'UUID': 'aaa'},
|
|
...
|
|
}
|
|
}
|
|
|
|
"""
|
|
|
|
# This dictionary maps gpt attributes the user can modify into the cgpt
|
|
# utility command line options.
|
|
ATTR_TO_COMMAND = {'priority': 'P', 'tries': 'T', 'successful': 'S'}
|
|
|
|
def __init__(self, os_if):
|
|
self.os_if = os_if
|
|
self.devices = {}
|
|
|
|
def read_device_info(self, dev_name):
|
|
"""Get device information from cgpt and parse it into a dictionary.
|
|
|
|
Inputs:
|
|
dev_name: a string the Linux storage device name, (i.e. '/dev/sda')
|
|
"""
|
|
|
|
device_dump = self.os_if.run_shell_command_get_output(
|
|
'cgpt show %s' % dev_name)
|
|
label = None
|
|
label_data = {}
|
|
device_data = {}
|
|
for line in [x.strip() for x in device_dump]:
|
|
if 'Label:' in line:
|
|
if label and label not in device_data:
|
|
device_data[label] = label_data
|
|
_, _, partition, _, label = line.split()
|
|
label = line.split('Label:')[1].strip('" ')
|
|
label_data = {'partition': int(partition)}
|
|
continue
|
|
if ':' in line:
|
|
name, value = line.strip().split(':')
|
|
if name != 'Attr':
|
|
label_data[name] = value.strip()
|
|
continue
|
|
# Attributes are split around '=', each attribute becomes a
|
|
# separate partition property.
|
|
attrs = value.strip().split()
|
|
for attr in attrs:
|
|
name, value = attr.split('=')
|
|
label_data[name] = int(value)
|
|
if label_data:
|
|
device_data[label] = label_data
|
|
|
|
self.devices[dev_name] = device_data
|
|
|
|
def get_partition(self, device, partition_name):
|
|
"""Retrieve a dictionary representing a partition on a device.
|
|
|
|
Inputs:
|
|
device: a string, the Linux device name
|
|
partition_name: a string, the partition name as reported by cgpt.
|
|
|
|
Raises:
|
|
CgptError in case the device or partiton on that device are not
|
|
known.
|
|
"""
|
|
|
|
try:
|
|
result = self.devices[device][partition_name]
|
|
except KeyError:
|
|
raise CgptError('could not retrieve partiton %s of device %s' %
|
|
(partition_name, device))
|
|
return result
|
|
|
|
def set_partition(self, device, partition_name, partition_value):
|
|
"""Set partition properties.
|
|
|
|
Inputs:
|
|
device: a string, the Linux device name
|
|
partition_name: a string, the partition name as reported by cgpt.
|
|
partiton_value: a dictionary, where keys are strings, names of the
|
|
properties which need to be modified, and values are the
|
|
values to set the properties to. The only properties which
|
|
can be modified are those which are keys of ATTR_TO_COMMAND
|
|
defined above.
|
|
Raises:
|
|
CgptError in case a property name is not known or not supposed to
|
|
be modified.
|
|
"""
|
|
|
|
current = self.get_partition(device, partition_name)
|
|
options = []
|
|
for prop, value in partition_value.iteritems():
|
|
try:
|
|
if value == current[prop]:
|
|
continue
|
|
options.append('-%s %d' % (self.ATTR_TO_COMMAND[prop], value))
|
|
except KeyError:
|
|
raise CgptError("unknown or immutable property '%s'" % prop)
|
|
|
|
if not options:
|
|
return
|
|
|
|
cgpt_add_cmd = 'cgpt add -i %d %s %s' % (current['partition'],
|
|
' '.join(options), device)
|
|
self.os_if.run_shell_command(cgpt_add_cmd, modifies_device=True)
|