os_interface.py revision c0168917ffb61c59c7746cd39fc53c1dd134723b
1c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam#!/usr/bin/python
2c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Use of this source code is governed by a BSD-style license that can be
4c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# found in the LICENSE file.
5c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
6c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam'''A module to provide interface to ChromeOS services.'''
7c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
8c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport datetime
9c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport os
10c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport re
11c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport shutil
12c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport struct
13c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport subprocess
14c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport tempfile
15c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport time
16c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
17c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass ChromeOSInterfaceError(Exception):
18c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    '''ChromeOS interface specific exception.'''
19c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    pass
20c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
21c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass Crossystem(object):
22c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    '''A wrapper for the crossystem utility.'''
23c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
24c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    # Code dedicated for user triggering recovery mode through crossystem.
25c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    USER_RECOVERY_REQUEST_CODE = '193'
26c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
27c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    '''
28c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    The first three legacy boot vector digits are the boot vector base (the
29c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    entire vector consists of 5 digits). They used to be reported by the BIOS
30c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    through ACPI, but that scheme has been superseded by the 'crossystem'
31c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    interface.
32c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
33c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    The digits of the boot vector base have the following significance
34c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
35c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    - first digit -
36c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    1 - normal boot
37c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    2 - developer mode boot
38c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    3 - recovery initialed by pressing the recovery button
39c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    4 - recovery from developer mode warning screen
40c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    5 - recovery caused by both firmware images being invalid
41c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    6 - recovery caused by both kernel images being invalid
42c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    8 - recovery initiated by user
43c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
44c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    - second digit -
45c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    0 - recovery firmware
46c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    1 - rewritable firmware A
47c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    2 - rewritable firmware B
48c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
49c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    - third digit -
50c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    0 - Read only (recovery) EC firmware
51c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    1 - rewritable EC firmware
52c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
53c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
54c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Below is a list of dictionaries to map current system state as reported by
55c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    'crossystem' into the 'legacy' boot vector digits.
56c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
57c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    The three elements of the list represent the three digits of the boot
58c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    vector. Each list element is a dictionary where the key is the legacy boot
59c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    vector value in the appropriate position, and the value is in turn a
60c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    dictionary of name-value pairs.
61c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
62c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    If all name-value pairs of a dictionary element match those reported by
63c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    crossystem, the legacy representation number is considered the appropriate
64c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    vector digit.
65c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
66c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Note that on some platforms (namely, Mario) same parameters returned by
67c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    crossystem are set to a wrong value. The class init() routine adjust the
68c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    list to support those platforms.
69c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    '''
70c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
71c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    VECTOR_MAPS = [
72c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        { # first vector position
73c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '1': {
74c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'devsw_boot': '0',
75c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'mainfw_type': 'normal',
76c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recoverysw_boot': '0',
77c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                },
78c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '2': {
79c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'devsw_boot': '1',
80c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'mainfw_type': 'developer',
81c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recoverysw_boot': '0',
82c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                },
83c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '3': {
84c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'devsw_boot': '0',
85c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'mainfw_type': 'recovery',
86c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recovery_reason' : '2',
87c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recoverysw_boot': '1',
88c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                },
89c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '4': {
90c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'devsw_boot': '1',
91c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'mainfw_type': 'recovery',
92c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recovery_reason' : '65',
93c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recoverysw_boot': '0',
94c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                },
95c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '5': {
96c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'devsw_boot': '0',
97c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'mainfw_type': 'recovery',
98c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recovery_reason' : ('3', '23', '27'),
99c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recoverysw_boot': '0',
100c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                },
101c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '6': {
102c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'devsw_boot': '0',
103c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'mainfw_type': 'recovery',
104c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recovery_reason' : '66',
105c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recoverysw_boot': '0',
106c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                },
107c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '8': {
108c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'devsw_boot': '0',
109c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'mainfw_type': 'recovery',
110c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recovery_reason' : USER_RECOVERY_REQUEST_CODE,
111c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                'recoverysw_boot': '0',
112c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                },
113c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            },
114c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        { # second vector position
115c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '0': {'mainfw_type': 'recovery',},
116c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '1': {'mainfw_act': 'A',},
117c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '2': {'mainfw_act': 'B',},
118c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            },
119c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        { # third vector position
120c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '0': {'ecfw_act': 'RO',},
121c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            '1': {'ecfw_act': 'RW',},
122c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            },
123c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ]
124c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
125c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def init(self, cros_if):
126c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Init the instance. If running on Mario - adjust the map.'''
127c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
128c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.cros_if = cros_if
129c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
130c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # Hack Alert!!! Adjust vector map to work on Mario
131c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        fwid = self.__getattr__('fwid').lower()
132c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not 'mario' in fwid:
133c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
134c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # Mario firmware is broken and always reports recovery switch as set
135c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # at boot time when booting up in recovery mode. This is why we
136c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # exclude recoverysw_boot from the map when running on mario.
137c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for state in self.VECTOR_MAPS[0].itervalues():
138c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if state['mainfw_type'] != 'recovery':
139c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                continue
140c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if 'recoverysw_boot' in state:
141c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                del(state['recoverysw_boot'])
142c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if state['recovery_reason'] == self.USER_RECOVERY_REQUEST_CODE:
143c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                # This is the only recovery reason Mario knows about
144c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                state['recovery_reason'] = '1'
145c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
146c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def __getattr__(self, name):
147c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
148c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Retrieve a crosssystem attribute.
149c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
150c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Attempt to access crossystemobject.name will invoke `crossystem name'
151c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        and return the stdout as the value.
152c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
153c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.cros_if.run_shell_command_get_output(
154c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            'crossystem %s' % name)[0]
155c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
156c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def __setattr__(self, name, value):
157c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if name in ('cros_if',):
158c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.__dict__[name] = value
159c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
160c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.cros_if.run_shell_command('crossystem "%s=%s"' % (name, value))
161c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
162c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def request_recovery(self):
163c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Request recovery mode next time the target reboots.'''
164c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
165c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.__setattr__('recovery_request', self.USER_RECOVERY_REQUEST_CODE)
166c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
167c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_boot_vector_base(self):
168c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Convert system state into a legacy boot vector base.
169c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
170c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        The function looks up the VECTOR_MAPS list above to find the digits
171c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        matching the current crossystem output, and returns a list of three
172c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        digits in symbolic representation, which become the base of the 5
173c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        digit boot state vector.
174c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
175c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Should it be impossible to interpret the state, the function returns
176c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        a partially built list, which is an indication of a problem for the
177c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        caller (list shorter than 3 elements).
178c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
179c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
180c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        boot_vector = []
181c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
182c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for vector_map in self.VECTOR_MAPS:
183c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            for (digit, values) in vector_map.iteritems():
184c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                for (name, value) in values.iteritems():
185c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    # Get the actual attribute value from crossystem.
186c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    attr_value = self.__getattr__(name)
187c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    if isinstance(value, str):
188c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                        if attr_value != value:
189c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                            break
190c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    else:
191c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                        # 'value' is a tuple of possible actual values.
192c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                        if attr_value not in value:
193c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                            break
194c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                else:
195c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    boot_vector.append(digit)
196c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    break
197c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
198c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return boot_vector
199c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
200c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def dump(self):
201c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Dump all crossystem values as multiline text.'''
202c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
203c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return '\n'.join(self.cros_if.run_shell_command_get_output(
204c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            'crossystem'))
205c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
206c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
207c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass ChromeOSInterface(object):
208c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    '''An object to encapsulate OS services functions.'''
209c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
210c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def __init__(self, silent):
211c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Object construction time initialization.
212c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
213c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        The only parameter is the Boolean 'silent', when True the instance
214c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        does not duplicate log messages on the console.
215c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
216c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
217c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.silent = silent
218c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.state_dir = None
219c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.log_file = None
220c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.cs = Crossystem()
221c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
222c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def init(self, state_dir=None, log_file=None):
223c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Initialize the ChromeOS interface object.
224c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Args:
225c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          state_dir - a string, the name of the directory (as defined by the
226c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                      caller). The contents of this directory persist over
227c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                      system restarts and power cycles.
228c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          log_file - a string, the name of the log file kept in the state
229c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                     directory.
230c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
231c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Default argument values support unit testing.
232c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
233c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
234c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.cs.init(self)
235c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.state_dir = state_dir
236c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
237c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if self.state_dir:
238c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if not os.path.exists(self.state_dir):
239c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                try:
240c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    os.mkdir(self.state_dir)
241c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                except OSError, err:
242c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    raise ChromeOSInterfaceError(err)
243c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if log_file:
244c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                if log_file[0] == '/':
245c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    self.log_file = log_file
246c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                else:
247c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    self.log_file = os.path.join(state_dir, log_file)
248c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
249c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def target_hosted(self):
250c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Return True if running on a ChromeOS target.'''
251c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        signature = open('/etc/lsb-release', 'r').readlines()[0]
252c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return re.search(r'chrom(ium|e)os', signature, re.IGNORECASE) != None
253c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
254c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def state_dir_file(self, file_name):
255c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Get a full path of a file in the state directory.'''
256c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return os.path.join(self.state_dir, file_name)
257c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
258c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def init_environment(self):
259c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Initialize Chrome OS interface environment.
260c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
261c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        If state dir was not set up by the constructor, create a temp
262c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        directory, otherwise create the directory defined during construction
263c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        of this object.
264c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
265c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Return the state directory name.
266c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
267c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
268c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.state_dir:
269c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.state_dir = tempfile.mkdtemp(suffix='_saft')
270c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
271c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            # Wipe out state directory, to start the state machine clean.
272c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            shutil.rmtree(self.state_dir)
273c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            # And recreate it
274c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.init(self.state_dir, self.log_file)
275c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
276c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.state_dir
277c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
278c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def shut_down(self, new_log='/var/saft_log.txt'):
279c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Destroy temporary environment so that the test can be restarted.'''
280c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if os.path.exists(self.log_file):
281c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            shutil.copyfile(self.log_file, new_log)
282c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        shutil.rmtree(self.state_dir)
283c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
284c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def log(self, text):
285c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Write text to the log file and print it on the screen, if enabled.
286c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
287c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      The entire log (maintained across reboots) can be found in
288c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      self.log_file.
289c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      '''
290c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
291c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # Don't print on the screen unless enabled.
292c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.silent:
293c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            print text
294c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
295c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.log_file or not os.path.exists(self.state_dir):
296c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            # Called before environment was initialized, ignore.
297c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
298c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
299c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        timestamp = datetime.datetime.strftime(
300c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            datetime.datetime.now(), '%I:%M:%S %p:')
301c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
302c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        log_f = open(self.log_file, 'a')
303c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        log_f.write('%s %s\n' % (timestamp, text))
304c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        log_f.close()
305c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
306c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def exec_exists(self, program):
307c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Check if the passed in string is a valid executable found in PATH.'''
308c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
309c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for path in os.environ['PATH'].split(os.pathsep):
310c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            exe_file = os.path.join(path, program)
311c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if (os.path.isfile(exe_file) or os.path.islink(exe_file)
312c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                ) and os.access(exe_file, os.X_OK):
313c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                return True
314c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return False
315c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
316c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def run_shell_command(self, cmd):
317c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Run a shell command.
318c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
319c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      In case of the command returning an error print its stdout and stderr
320c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      outputs on the console and dump them into the log. Otherwise suppress all
321c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      output.
322c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
323c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      In case of command error raise an OSInterfaceError exception.
324c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
325c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      Return the subprocess.Popen() instance to provide access to console
326c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      output in case command succeeded.
327c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      '''
328c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
329c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.log('Executing %s' % cmd)
330c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
331c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                             stderr=subprocess.PIPE)
332c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        process.wait()
333c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if process.returncode:
334c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            err = ['Failed running: %s' % cmd]
335c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            err.append('stdout:')
336c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            err.append(process.stdout.read())
337c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            err.append('stderr:')
338c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            err.append(process.stderr.read())
339c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            text = '\n'.join(err)
340c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            print text
341c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self.log(text)
342c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise ChromeOSInterfaceError('command %s failed' % cmd)
343c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return process
344c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
345c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def is_removable_device(self, device):
346c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Check if a certain storage device is removable.
347c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
348c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        device - a string, file name of a storage device or a device partition
349c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                 (as in /dev/sda[0-9] or /dev/mmcblk0p[0-9]).
350c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
351c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Returns True if the device is removable, False if not.
352c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
353c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
354c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.target_hosted():
355c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return False
356c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
357c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # Drop trailing digit(s) and letter(s) (if any)
358c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        base_dev = self.strip_part(device.split('/')[2])
359c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        removable = int(open('/sys/block/%s/removable' % base_dev, 'r').read())
360c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
361c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return removable == 1
362c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
363c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_internal_disk(self, device):
364c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Get the internal disk by given the current disk.
365c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
366c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        If device is removable device, internal disk is decided by which kind
367c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        of divice (arm or x86). Otherwise, return device itself.
368c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
369c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        device - a string, file name of a storage device or a device partition
370c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                 (as in /dev/sda[0-9] or /dev/mmcblk0p[0-9]).
371c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
372c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Return internal kernel disk.
373c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
374c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if self.is_removable_device(device):
375c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if os.path.exists('/dev/mmcblk1'):
376c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                return '/dev/mmcblk1'
377c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            else:
378c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                return '/dev/sda'
379c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
380c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return self.strip_part(device)
381c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
382c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_root_part(self):
383c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Return a string, the name of root device with partition number'''
384c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.run_shell_command_get_output('rootdev -s')[0]
385c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
386c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_root_dev(self):
387c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Return a string, the name of root device without partition number'''
388c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.strip_part(self.get_root_part())
389c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
390c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def join_part(self, dev, part):
391c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Return a concatenated string of device and partition number'''
392c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if 'mmcblk' in dev:
393c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return dev + 'p' + part
394c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
395c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return dev + part
396c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
397c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def strip_part(self, dev_with_part):
398c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Return a stripped string without partition number'''
399c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        dev_name_stripper = re.compile('p?[0-9]+$')
400c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return dev_name_stripper.sub('', dev_with_part)
401c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
402c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def run_shell_command_get_output(self, cmd):
403c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Run shell command and return its console output to the caller.
404c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
405c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      The output is returned as a list of strings stripped of the newline
406c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      characters.'''
407c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
408c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        process = self.run_shell_command(cmd)
409c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return [x.rstrip() for x in process.stdout.readlines()]
410c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
411c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def boot_state_vector(self):
412c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Read and return to caller a string describing the system state.
413c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
414c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        The string has a form of x0:x1:x2:<removable>:<partition_number>,
415c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        where the field meanings of X# are described in the
416c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Crossystem.get_boot_vector_base() docstring above.
417c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
418c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        <removable> is set to 1 or 0 depending if the root device is removable
419c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        or not, and <partition number> is the last element of the root device
420c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        name, designating the partition where the root fs is mounted.
421c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
422c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        This vector fully describes the way the system came up.
423c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
424c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
425c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        state = self.cs.get_boot_vector_base()
426c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
427c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if len(state) != 3:
428c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise ChromeOSInterfaceError(self.cs.dump())
429c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
430c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        root_part = self.get_root_part()
431c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        state.append('%d' % int(self.is_removable_device(root_part)))
432c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        state.append('%s' % root_part[-1])
433c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        state_str = ':'.join(state)
434c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return state_str
435c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
436c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def cmp_boot_vector(self, vector1, vector2):
437c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Compare if the two boot vectors are the same
438c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
439c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Note: a wildcard (*) will match any value.
440c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
441c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        list1 = vector1.split(':')
442c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        list2 = vector2.split(':')
443c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if len(list1) != len(list2):
444c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise ChromeOSInterfaceError(
445c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    'Boot vectors (%s %s) should be of the same length'
446c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    % (vecotr1, vector2))
447c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for i in range(len(list1)):
448c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if list1[i] != list2[i] and list1[i] != '*' and list2[i] != '*':
449c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                return False
450c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return True
451c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
452c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_writeable_mount_point(self, dev, tmp_dir):
453c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Get mountpoint of the passed in device mounted in read/write mode.
454c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
455c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      If the device is already mounted and is writeable - return its mount
456c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      point. If the device is mounted but read-only - remount it read/write
457c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      and return its mount point. If the device is not mounted - mount it read
458c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      write on the passsed in path and return this path.
459c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      '''
460c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
461c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      # The device root file system is mounted on is represented as /dev/root
462c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      # otherwise.
463c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        options_filter = re.compile('.*\((.+)\).*')
464c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        root_part = self.get_root_part()
465c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if dev == root_part:
466c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            dev = '/dev/root'
467c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
468c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for line in self.run_shell_command_get_output('mount'):
469c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if not line.startswith('%s ' % dev):
470c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                continue
471c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            mount_options = options_filter.match(line).groups(0)[0]
472c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # found mounted
473c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if 'ro' in mount_options.split(','):
474c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          # mounted read only
475c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                self.run_shell_command('mount -o remount,rw %s' % dev)
476c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return line.split()[2]  # Mountpoint is the third element.
477c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam      # Not found, needs to be mounted
478c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.run_shell_command('mount %s %s' % (dev, tmp_dir))
479c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return tmp_dir
480c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
481c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def retrieve_body_version(self, blob):
482c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Given a blob, retrieve body version.
483c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
484c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Currently works for both, firmware and kernel blobs. Returns '-1' in
485c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        case the version can not be retrieved reliably.
486c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
487c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        header_format = '<8s8sQ'
488c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        preamble_format = '<40sQ'
489c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        magic, _, kb_size = struct.unpack_from(header_format, blob)
490c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
491c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if magic != 'CHROMEOS':
492c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return -1  # This could be a corrupted version case.
493c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
494c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        _, version = struct.unpack_from(preamble_format, blob, kb_size)
495c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return version
496c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
497c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def retrieve_datakey_version(self, blob):
498c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Given a blob, retrieve firmware data key version.
499c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
500c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Currently works for both, firmware and kernel blobs. Returns '-1' in
501c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        case the version can not be retrieved reliably.
502c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
503c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        header_format = '<8s96sQ'
504c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        magic, _, version = struct.unpack_from(header_format, blob)
505c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if magic != 'CHROMEOS':
506c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return -1 # This could be a corrupted version case.
507c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return version
508c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
509c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def retrieve_kernel_subkey_version(self, blob):
510c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Given a blob, retrieve kernel subkey version.
511c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
512c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        It is in firmware vblock's preamble.
513c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
514c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
515c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        header_format = '<8s8sQ'
516c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        preamble_format = '<72sQ'
517c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        magic, _, kb_size = struct.unpack_from(header_format, blob)
518c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
519c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if magic != 'CHROMEOS':
520c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return -1
521c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
522c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        _, version = struct.unpack_from(preamble_format, blob, kb_size)
523c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return version
524c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
525c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def retrieve_preamble_flags(self, blob):
526c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Given a blob, retrieve preamble flags if available.
527c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
528c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        It only works for firmware. If the version of preamble header is less
529c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        than 2.1, no preamble flags supported, just returns 0.
530c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''
531c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        header_format = '<8s8sQ'
532c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        preamble_format = '<32sII64sI'
533c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        magic, _, kb_size = struct.unpack_from(header_format, blob)
534c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
535c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if magic != 'CHROMEOS':
536c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return -1  # This could be a corrupted version case.
537c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
538c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        _, ver, subver, _, flags = struct.unpack_from(preamble_format, blob,
539c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                                                      kb_size)
540c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
541c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if ver > 2 or (ver == 2 and subver >= 1):
542c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return flags
543c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
544c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return 0  # Returns 0 if preamble flags not available.
545c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
546c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def read_partition(self, partition, size):
547c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        '''Read the requested partition, up to size bytes.'''
548c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        tmp_file = self.state_dir_file('part.tmp')
549c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.run_shell_command('dd if=%s of=%s bs=1 count=%d' % (
550c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                partition, tmp_file, size))
551c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        fileh = open(tmp_file, 'r')
552c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        data = fileh.read()
553c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        fileh.close()
554c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        os.remove(tmp_file)
555c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return data
556