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