| 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 |