| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 '''A module to provide interface to ChromeOS services.''' | 6 '''A module to provide interface to ChromeOS services.''' |
| 7 | 7 |
| 8 import datetime | 8 import datetime |
| 9 import os | 9 import os |
| 10 import re | 10 import re |
| 11 import shutil | 11 import shutil |
| 12 import struct | 12 import struct |
| 13 import subprocess | 13 import subprocess |
| 14 import tempfile | 14 import tempfile |
| 15 import time | 15 import time |
| 16 | 16 |
| 17 class ChromeOSInterfaceError(Exception): | 17 class ChromeOSInterfaceError(Exception): |
| 18 '''ChromeOS interface specific exception.''' | 18 '''ChromeOS interface specific exception.''' |
| 19 pass | 19 pass |
| 20 | 20 |
| 21 class Crossystem(object): | 21 class Crossystem(object): |
| 22 '''A wrapper for the crossystem utility.''' | 22 '''A wrapper for the crossystem utility.''' |
| 23 | 23 |
| 24 # Code dedicated for user triggering recovery mode through crossystem. |
| 25 USER_RECOVERY_REQUEST_CODE = '193' |
| 26 |
| 27 ''' |
| 28 The first three legacy boot vector digits are the boot vector base (the |
| 29 entire vector consists of 5 digits). They used to be reported by the BIOS |
| 30 through ACPI, but that scheme has been superseded by the 'crossystem' |
| 31 interface. |
| 32 |
| 33 The digits of the boot vector base have the following significance |
| 34 |
| 35 - first digit - |
| 36 1 - normal boot |
| 37 2 - developer mode boot |
| 38 3 - recovery initialed by pressing the recovery button |
| 39 4 - recovery from developer mode warning screen |
| 40 5 - recovery caused by both firmware images being invalid |
| 41 6 - recovery caused by both kernel images being invalid |
| 42 8 - recovery initiated by user |
| 43 |
| 44 - second digit - |
| 45 0 - recovery firmware |
| 46 1 - rewritable firmware A |
| 47 2 - rewritable firmware B |
| 48 |
| 49 - third digit - |
| 50 0 - Read only (recovery) EC firmware |
| 51 1 - rewritable EC firmware |
| 52 |
| 53 |
| 54 Below is a list of dictionaries to map current system state as reported by |
| 55 'crossystem' into the 'legacy' boot vector digits. |
| 56 |
| 57 The three elements of the list represent the three digits of the boot |
| 58 vector. Each list element is a dictionary where the key is the legacy boot |
| 59 vector value in the appropriate position, and the value is in turn a |
| 60 dictionary of name-value pairs. |
| 61 |
| 62 If all name-value pairs of a dictionary element match those reported by |
| 63 crossystem, the legacy representation number is considered the appropriate |
| 64 vector digit. |
| 65 |
| 66 Note that on some platforms (namely, Mario) same parameters returned by |
| 67 crossystem are set to a wrong value. The class init() routine adjust the |
| 68 list to support those platforms. |
| 69 ''' |
| 70 |
| 71 VECTOR_MAPS = [ |
| 72 { # first vector position |
| 73 '1': { |
| 74 'devsw_boot': '0', |
| 75 'mainfw_type': 'normal', |
| 76 'recoverysw_boot': '0', |
| 77 }, |
| 78 '5': { |
| 79 'devsw_boot': '0', |
| 80 'recoverysw_boot': '0', |
| 81 'recovery_reason' : '3', |
| 82 'mainfw_type': 'recovery', |
| 83 }, |
| 84 '6': { |
| 85 'devsw_boot': '0', |
| 86 'recoverysw_boot': '0', |
| 87 'recovery_reason' : '66', |
| 88 'mainfw_type': 'recovery', |
| 89 }, |
| 90 '8': { |
| 91 'devsw_boot': '0', |
| 92 'recoverysw_boot': '0', |
| 93 'recovery_reason' : USER_RECOVERY_REQUEST_CODE, |
| 94 'mainfw_type': 'recovery', |
| 95 }, |
| 96 }, |
| 97 { # second vector position |
| 98 '0': {'mainfw_type': 'recovery',}, |
| 99 '1': { |
| 100 'mainfw_type': 'normal', |
| 101 'mainfw_act': 'A' |
| 102 }, |
| 103 '2': { |
| 104 'mainfw_type': 'normal', |
| 105 'mainfw_act': 'B' |
| 106 }, |
| 107 }, |
| 108 { # third vector position |
| 109 '0': {'ecfw_act': 'RO',}, |
| 110 '1': {'ecfw_act': 'RW',}, |
| 111 }, |
| 112 ] |
| 113 |
| 24 def init(self, cros_if): | 114 def init(self, cros_if): |
| 115 '''Init the instance. If running on Mario - adjust the map.''' |
| 116 |
| 25 self.cros_if = cros_if | 117 self.cros_if = cros_if |
| 26 | 118 |
| 119 # Hack Alert!!! Adjust vector map to work on Mario |
| 120 fwid = self.__getattr__('fwid').lower() |
| 121 if not 'mario' in fwid: |
| 122 return |
| 123 # Mario firmware is broken and always reports recovery switch as set |
| 124 # at boot time when booting up in recovery mode. This is why we |
| 125 # exclude recoverysw_boot from the map when running on mario. |
| 126 for state in self.VECTOR_MAPS[0].itervalues(): |
| 127 if state['mainfw_type'] != 'recovery': |
| 128 continue |
| 129 if 'recoverysw_boot' in state: |
| 130 del(state['recoverysw_boot']) |
| 131 if state['recovery_reason'] == self.USER_RECOVERY_REQUEST_CODE: |
| 132 # This is the only recovery reason Mario knows about |
| 133 state['recovery_reason'] = '1' |
| 134 |
| 27 def __getattr__(self, name): | 135 def __getattr__(self, name): |
| 28 ''' | 136 ''' |
| 29 Retrieve a crosssystem attribute. | 137 Retrieve a crosssystem attribute. |
| 30 | 138 |
| 31 Attempt to access crossystemobject.name will invoke `crossystem name' | 139 Attempt to access crossystemobject.name will invoke `crossystem name' |
| 32 and return the stdout as the value. | 140 and return the stdout as the value. |
| 33 ''' | 141 ''' |
| 34 return self.cros_if.run_shell_command_get_output( | 142 return self.cros_if.run_shell_command_get_output( |
| 35 'crossystem %s' % name)[0] | 143 'crossystem %s' % name)[0] |
| 36 | 144 |
| 37 def __setattr__(self, name, value): | 145 def __setattr__(self, name, value): |
| 38 if name in ('cros_if',): | 146 if name in ('cros_if',): |
| 39 self.__dict__[name] = value | 147 self.__dict__[name] = value |
| 40 else: | 148 else: |
| 41 self.cros_if.run_shell_command('crossystem "%s=%s"' % (name, value)) | 149 self.cros_if.run_shell_command('crossystem "%s=%s"' % (name, value)) |
| 42 | 150 |
| 151 def request_recovery(self): |
| 152 '''Request recovery mode next time the target reboots.''' |
| 153 |
| 154 self.__setattr__('recovery_request', self.USER_RECOVERY_REQUEST_CODE) |
| 43 | 155 |
| 44 def get_boot_vector_base(self): | 156 def get_boot_vector_base(self): |
| 45 ''' | 157 '''Convert system state into a legacy boot vector base. |
| 46 Convert system state into a legacy boot vector base. | |
| 47 | 158 |
| 48 The first three legacy boot vector digits are the boot vector base | 159 The function looks up the VECTOR_MAPS list above to find the digits |
| 49 (the entire vector consists of 5 digits). They used to be reported by | 160 matching the current crossystem output, and returns a list of three |
| 50 the BIOS through ACPI, but that scheme has been superseded by the | 161 digits in symbolic representation, which become the base of the 5 |
| 51 'crossystem' interface. | 162 digit boot state vector. |
| 52 | 163 |
| 53 The digits of the boot vector base have the following significance | 164 Should it be impossible to interpret the state, the function returns |
| 54 | 165 a partially built list, which is an indication of a problem for the |
| 55 - first digit - | |
| 56 1 - normal boot | |
| 57 2 - developer mode boot | |
| 58 3 - recovery initialed by pressing the recovery button | |
| 59 4 - recovery from developer mode warning screen | |
| 60 5 - recovery caused by both firmware images being invalid | |
| 61 6 - recovery caused by both kernel images being invalid | |
| 62 | |
| 63 - second digit - | |
| 64 0 - recovery firmware | |
| 65 1 - rewritable firmware A | |
| 66 2 - rewritable firmware B | |
| 67 | |
| 68 - third digit - | |
| 69 0 - Read only (recovery) EC firmware | |
| 70 1 - rewritable EC firmware | |
| 71 | |
| 72 | |
| 73 This function uses a three tuple of dictionaries to map current system | |
| 74 state as reported by 'crossystem' into the 'legacy' boot vector | |
| 75 digits. | |
| 76 | |
| 77 Each tuple element is a dictionary, where the key is the 'legacy' | |
| 78 representation of the state, and the value is a yet another dictionary | |
| 79 of name-value pairs. | |
| 80 | |
| 81 If all name-value pairs match those in the crossystem output, the | |
| 82 legacy representation number is returned as the appropriate vector | |
| 83 number. | |
| 84 | |
| 85 The function returns a list of three digits in symbolic representation. | |
| 86 | |
| 87 Should it be impossible to interpret the state, the function returns a | |
| 88 partially built list, which is an indication of a problem for the | |
| 89 caller (list shorter than 3 elements). | 166 caller (list shorter than 3 elements). |
| 90 ''' | 167 ''' |
| 91 | 168 |
| 92 vector_maps = ( | |
| 93 { # first vector position | |
| 94 '1': { | |
| 95 'devsw_boot': '0', | |
| 96 'recoverysw_boot': '0', | |
| 97 'recovery_reason' : '0', | |
| 98 'tried_fwb' : '0', | |
| 99 }, | |
| 100 }, | |
| 101 { # second vector position | |
| 102 '0': {'mainfw_type': 'recovery',}, | |
| 103 '1': { | |
| 104 'mainfw_type': 'normal', | |
| 105 'mainfw_act': 'A' | |
| 106 }, | |
| 107 '2': { | |
| 108 'mainfw_type': 'normal', | |
| 109 'mainfw_act': 'B' | |
| 110 }, | |
| 111 }, | |
| 112 { # third vector position | |
| 113 '0': {'ecfw_act': 'RO',}, | |
| 114 '1': {'ecfw_act': 'RW',}, | |
| 115 }, | |
| 116 ) | |
| 117 | |
| 118 boot_vector = [] | 169 boot_vector = [] |
| 119 | 170 |
| 120 for vector_map in vector_maps: | 171 for vector_map in self.VECTOR_MAPS: |
| 121 for (digit, values) in vector_map.iteritems(): | 172 for (digit, values) in vector_map.iteritems(): |
| 122 for (name, value) in values.iteritems(): | 173 for (name, value) in values.iteritems(): |
| 123 if self.__getattr__(name) != value: | 174 if self.__getattr__(name) != value: |
| 124 break | 175 break |
| 125 else: | 176 else: |
| 126 boot_vector.append(digit) | 177 boot_vector.append(digit) |
| 127 break | 178 break |
| 128 | 179 |
| 129 return boot_vector | 180 return boot_vector |
| 130 | 181 |
| 131 def dump(self): | 182 def dump(self): |
| 132 '''Dump all values as multiline text.''' | 183 '''Dump all crossystem values as multiline text.''' |
| 184 |
| 133 return '\n'.join(self.cros_if.run_shell_command_get_output( | 185 return '\n'.join(self.cros_if.run_shell_command_get_output( |
| 134 'crossystem')) | 186 'crossystem')) |
| 135 | 187 |
| 136 | 188 |
| 137 class ChromeOSInterface(object): | 189 class ChromeOSInterface(object): |
| 138 '''An object to encapsulate OS services functions.''' | 190 '''An object to encapsulate OS services functions.''' |
| 139 | 191 |
| 140 def __init__(self, silent): | 192 def __init__(self, silent): |
| 141 '''Object construction time initialization. | 193 '''Object construction time initialization. |
| 142 | 194 |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 def read_partition(self, partition, size): | 428 def read_partition(self, partition, size): |
| 377 '''Read the requested partition, up to size bytes.''' | 429 '''Read the requested partition, up to size bytes.''' |
| 378 tmp_file = self.state_dir_file('part.tmp') | 430 tmp_file = self.state_dir_file('part.tmp') |
| 379 self.run_shell_command('dd if=%s of=%s bs=1 count=%d' % ( | 431 self.run_shell_command('dd if=%s of=%s bs=1 count=%d' % ( |
| 380 partition, tmp_file, size)) | 432 partition, tmp_file, size)) |
| 381 fileh = open(tmp_file, 'r') | 433 fileh = open(tmp_file, 'r') |
| 382 data = fileh.read() | 434 data = fileh.read() |
| 383 fileh.close() | 435 fileh.close() |
| 384 os.remove(tmp_file) | 436 os.remove(tmp_file) |
| 385 return data | 437 return data |
| OLD | NEW |