Home | History | Annotate | Download | only in utils
      1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """A module to provide interface to gpt information.
      6 
      7 gpt stands for GUID partition table, it is a data structure describing
      8 partitions present of a storage device. cgpt is a utility which allows to read
      9 and modify gpt. This module parses cgpt output to create a dictionary
     10 including information about all defined partitions including their properties.
     11 It also allows to modify partition properties as required.
     12 """
     13 
     14 class CgptError(Exception):
     15     pass
     16 
     17 class CgptHandler(object):
     18     """Object representing one or more gpts present in the system.
     19 
     20     Attributes:
     21       os_if: an instance of OSInterface, initialized by the caller.
     22       devices: a dictionary keyed by the storage device names (as in
     23                /dev/sda), the contents are dictionaries of cgpt information,
     24                where keys are partiton names, and contents are in turn
     25                dictionaries of partition properties, something like the below
     26                (compressed for brevity):
     27       {'/dev/sda': {
     28         'OEM': {'partition': 8, 'Type': 'Linux data', 'UUID': 'xxx'},
     29         'ROOT-A': {'partition': 3, 'Type': 'ChromeOS rootfs', 'UUID': 'xyz'},
     30         'ROOT-C': {'partition': 7, 'Type': 'ChromeOS rootfs', 'UUID': 'xzz'},
     31         'ROOT-B': {'partition': 5, 'Type': 'ChromeOS rootfs', 'UUID': 'aaa'},
     32         ...
     33         }
     34      }
     35 
     36     """
     37 
     38     # This dictionary maps gpt attributes the user can modify into the cgpt
     39     # utility command line options.
     40     ATTR_TO_COMMAND = {
     41         'priority' : 'P',
     42         'tries' : 'T',
     43         'successful' : 'S'
     44         }
     45 
     46     def __init__(self, os_if):
     47         self.os_if = os_if
     48         self.devices = {}
     49 
     50     def read_device_info(self, dev_name):
     51         """Get device information from cgpt and parse it into a dictionary.
     52 
     53         Inputs:
     54           dev_name: a string the Linux storage device name, (i.e. '/dev/sda')
     55         """
     56 
     57         device_dump = self.os_if.run_shell_command_get_output(
     58             'cgpt show %s' % dev_name)
     59         label = None
     60         label_data = {}
     61         device_data = {}
     62         for line in [x.strip() for x in device_dump]:
     63             if 'Label:' in line:
     64                 if label and label not in device_data:
     65                     device_data[label] = label_data
     66                 _, _, partition, _, label = line.split()
     67                 label = line.split('Label:')[1].strip('" ')
     68                 label_data = {'partition': int(partition)}
     69                 continue
     70             if ':' in line:
     71                 name, value = line.strip().split(':')
     72                 if name != 'Attr':
     73                     label_data[name] = value.strip()
     74                     continue
     75                 # Attributes are split around '=', each attribute becomes a
     76                 # separate partition property.
     77                 attrs = value.strip().split()
     78                 for attr in attrs:
     79                     name, value = attr.split('=')
     80                     label_data[name] = int(value)
     81         if label_data:
     82             device_data[label] = label_data
     83 
     84         self.devices[dev_name] = device_data
     85 
     86     def get_partition(self, device, partition_name):
     87         """Retrieve a dictionary representing a partition on a device.
     88 
     89         Inputs:
     90           device: a string, the Linux device name
     91           partition_name: a string, the partition name as reported by cgpt.
     92 
     93         Raises:
     94           CgptError in case the device or partiton on that device are not
     95           known.
     96         """
     97 
     98         try:
     99             result = self.devices[device][partition_name]
    100         except KeyError:
    101             raise CgptError('could not retrieve partiton %s of device %s' % (
    102                     partition_name, device))
    103         return result
    104 
    105     def set_partition(self, device, partition_name, partition_value):
    106         """Set partition properties.
    107 
    108         Inputs:
    109           device: a string, the Linux device name
    110           partition_name: a string, the partition name as reported by cgpt.
    111           partiton_value: a dictionary, where keys are strings, names of the
    112                   properties which need to be modified, and values are the
    113                   values to set the properties to. The only properties which
    114                   can be modified are those which are keys of ATTR_TO_COMMAND
    115                   defined above.
    116         Raises:
    117           CgptError in case a property name is not known or not supposed to
    118               be modified.
    119         """
    120 
    121         current = self.get_partition(device, partition_name)
    122         options = []
    123         for prop, value in partition_value.iteritems():
    124             try:
    125                 if value == current[prop]:
    126                     continue
    127                 options.append('-%s %d' % (
    128                         self.ATTR_TO_COMMAND[prop], value))
    129             except KeyError:
    130                 raise CgptError("unknown or immutable property '%s'" % prop)
    131 
    132         if not options:
    133             return
    134 
    135         command = 'cgpt add -i %d %s %s' % (
    136             current['partition'], ' '.join(options), device)
    137         self.os_if.run_shell_command(command)
    138