blob: 5ea465ee39f867b1f675512a6823f039cd04a855 [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Tammo Spalink01e11722012-07-24 10:17:54 -07002# pylint: disable=E1101
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08003#
4# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Google Factory Tool.
9
10This tool is indended to be used on factory assembly lines. It
11provides all of the Google required test functionality and must be run
12on each device as part of the assembly process.
13"""
14
15
16import logging
17import os
Jon Salz65266432012-07-30 19:02:49 +080018import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080019import re
20import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080021import time
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080022
Tammo Spalink8fab5312012-05-28 18:33:30 +080023from tempfile import gettempdir, NamedTemporaryFile
Tammo Spalink86a61c62012-05-25 15:10:35 +080024
Tammo Spalinka40293e2012-07-04 14:58:56 +080025import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080026
Jon Salz0f8a6842012-09-25 11:28:22 +080027from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070028from cros.factory.common import YamlWrite
Tammo Spalink01e11722012-07-24 10:17:54 -070029from cros.factory.gooftool import crosfw
30from cros.factory.gooftool import report_upload
31from cros.factory.gooftool.bmpblk import unpack_bmpblock
Andy Cheng8ece7382012-08-22 16:25:42 +080032from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080033from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
Jon Salz05aba9d2012-10-05 17:25:38 +080034from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA, FilterVPD
Tammo Spalinka40293e2012-07-04 14:58:56 +080035from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
36from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070037from cros.factory.hwdb import hwid_tool
Jon Salz83591782012-06-26 11:09:58 +080038from cros.factory.event_log import EventLog, EVENT_LOG_DIR
39from cros.factory.event_log import TimedUuid
cychiang7fe09372012-07-04 14:31:23 +080040from cros.factory.test.factory import FACTORY_LOG_PATH
Tammo Spalink86a61c62012-05-25 15:10:35 +080041
Tammo Spalink5c699832012-07-03 17:50:39 +080042
Tammo Spalink86a61c62012-05-25 15:10:35 +080043# Use a global event log, so that only a single log is created when
44# gooftool is called programmatically.
45_event_log = EventLog('gooftool')
46
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080047
48def GetPrimaryDevicePath(partition=None):
49 def IsFixed(dev):
50 sysfs_path = '/sys/block/%s/removable' % dev
51 return (os.path.exists(sysfs_path) and
52 open(sysfs_path).read().strip() == '0')
53 alpha_re = re.compile(r'^/dev/([a-zA-Z]+)[0-9]+$')
54 alnum_re = re.compile(r'^/dev/([a-zA-Z]+[0-9]+)p[0-9]+$')
cychiangde1dee22012-05-22 09:42:09 +080055 matched_alnum = False
56 dev_set = set()
57 for path in Shell('cgpt find -t rootfs').stdout.strip().split():
58 for dev in alpha_re.findall(path):
59 if IsFixed(dev):
60 dev_set.add(dev)
61 matched_alnum = False
62 for dev in alnum_re.findall(path):
63 if IsFixed(dev):
64 dev_set.add(dev)
65 matched_alnum = True
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080066 if len(dev_set) != 1:
67 raise Error('zero or multiple primary devs: %s' % dev_set)
68 dev_path = os.path.join('/dev', dev_set.pop())
69 if partition is None:
70 return dev_path
cychiangde1dee22012-05-22 09:42:09 +080071 fmt_str = '%sp%d' if matched_alnum else '%s%d'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080072 return fmt_str % (dev_path, partition)
73
74
75def GetReleaseRootPartitionPath():
76 return GetPrimaryDevicePath(5)
77
78
79def GetReleaseKernelPartitionPath():
80 return GetPrimaryDevicePath(4)
81
82
83def FindScript(script_name):
Hung-Te Linb7313ca2012-07-31 15:27:57 +080084 # __file__ is in /usr/local/factory/py/gooftool/gooftool.py
85 # scripts should be in /usr/local/factory/sh/*
86 factory_base = os.path.realpath(os.path.join(
87 os.path.dirname(os.path.realpath(__file__)), '..', '..'))
88 script_path = os.path.join(factory_base, 'sh', script_name)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080089 if not os.path.exists(script_path):
90 raise Error('Needed script %s does not exist.' % script_path)
91 return script_path
92
93
Tammo Spalink5c699832012-07-03 17:50:39 +080094# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
95# treat that specially (as a smoot exit, as opposed to the more
96# verbose output for generic Error).
97
98
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080099@Command('write_hwid',
100 CmdArg('hwid', metavar='HWID', help='HWID string'))
101def WriteHwid(options):
102 """Write specified HWID value into the system BB."""
Tammo Spalink95c43732012-07-25 15:57:14 -0700103 logging.info('writing hwid string %r', options.hwid)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800104 main_fw = crosfw.LoadMainFirmware()
105 Shell('gbb_utility --set --hwid="%s" "%s"' %
106 (options.hwid, main_fw.GetFileName()))
107 main_fw.Write(sections=['GBB'])
Tammo Spalink86a61c62012-05-25 15:10:35 +0800108 _event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700109 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800110
111
Tammo Spalink8fab5312012-05-28 18:33:30 +0800112_hwdb_path_cmd_arg = CmdArg(
113 '--hwdb_path', metavar='PATH',
114 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
115 help='Path to the HWID database.')
116
Tammo Spalink95c43732012-07-25 15:57:14 -0700117_hwid_status_list_cmd_arg = CmdArg(
118 '--status', nargs='*', default=['supported'],
119 help='allow only HWIDs with these status values')
120
Jon Salzce124fb2012-10-02 17:42:03 +0800121_probe_results_cmd_arg = CmdArg(
122 '--probe_results', metavar='RESULTS.yaml',
123 help=('Output from "gooftool probe" (used instead of '
124 'probing this system).'))
125
126_hwid_cmd_arg = CmdArg(
127 '--hwid', metavar='HWID',
128 help=('HWID to verify (instead of the currently set HWID of '
129 'this system)'))
130
Tammo Spalink95c43732012-07-25 15:57:14 -0700131
132@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800133 _hwdb_path_cmd_arg,
134 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700135 help='optional BOARD name, needed only if data is present '
136 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800137 CmdArg('--bom', metavar='BOM', help='BOM name'),
138 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800139 CmdArg('--optimistic', action='store_true',
140 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700141 CmdArg('--comps', nargs='*', default=[],
142 help='list of canonical component names'),
143 CmdArg('--missing', nargs='*', default=[],
144 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800145 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700146 help='consider only HWIDs within this list of status values'))
147def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800148 """Determine a list of possible HWIDs using provided args and probeing.
149
150 VOLATILE can always be determined by probing. To get a unique
151 result, VARIANT must be specified for all cases where the matching
152 BOM has more than one associated variant code, otherwise all HWID
153 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700154 alternatively be specified using the --stdin_comps argument, which
155 allows specifying a list of canonical names (one per line) on stdin,
156 one per line. Based on what is known from BOM and stdin_comps,
157 determine a list of components to probe for, and use those probe
158 results to resolve a list of matching HWIDs. If no boms,
159 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800160 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800161
162 Returns (on stdout): A list of HWIDs that match the available probe
163 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700164
165 Example:
166
167 // Three ways to specify a keyboard (assuming it is a variant component)
168 gooftool best_match_hwids --missing keyboard
169 gooftool best_match_hwids --variant A or
170 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800171 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800172 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700173 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800174 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800175 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800176 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800177 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800178 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700179 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800180 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800181 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800182 device.VariantExists(options.variant)
183 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700184 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700185 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700186 % YamlWrite(sorted(
187 hwid_tool.ComponentSpecClasses(component_spec) &
188 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700189 component_spec = hwid_tool.CombineComponentSpecs(
190 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700191 if options.comps or options.missing:
192 map(comp_db.CompExists, options.comps)
193 map(comp_db.CompClassExists, options.missing)
194 extra_comp_spec = comp_db.CreateComponentSpec(
195 components=options.comps,
196 missing=options.missing)
197 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
198 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
199 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700200 % YamlWrite(sorted(
201 hwid_tool.ComponentSpecClasses(component_spec) &
202 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700203 component_spec = hwid_tool.CombineComponentSpecs(
204 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700205 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700206 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800207 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800208 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
209 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700210 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700211 'as inputs, and cannot be probed for:\n%s'
212 'This problem can often be addressed by specifying all of '
213 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800214 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700215 print 'probing for missing classes:'
216 print YamlWrite(list(missing_classes))
217 probe_results = Probe(target_comp_classes=list(missing_classes),
218 probe_volatile=False, probe_initial_config=False)
219 cooked_components = comp_db.MatchComponentProbeValues(
220 probe_results.found_probe_value_map)
221 if cooked_components.unmatched:
222 sys.exit('ERROR: some probed components are unrecognized:\n%s'
223 % YamlWrite(cooked_components.unmatched))
224 probed_comp_spec = comp_db.CreateComponentSpec(
225 components=cooked_components.matched,
226 missing=probe_results.missing_component_classes)
227 component_spec = hwid_tool.CombineComponentSpecs(
228 component_spec, probed_comp_spec)
229 print YamlWrite({'component data used for matching': {
230 'missing component classes': component_spec.classes_missing,
231 'found components': component_spec.components}})
232 component_data = hwid_tool.ComponentData(
233 extant_components=hwid_tool.ComponentSpecCompClassMap(
234 component_spec).keys(),
235 classes_missing=component_spec.classes_missing)
236 match_tree = device.BuildMatchTree(component_data)
237 if not match_tree:
238 sys.exit('FAILURE: NO matching BOMs found')
239 print 'potential BOMs/VARIANTs:'
240 potential_variants = set()
241 potential_volatiles = set()
242 for bom_name, variant_tree in match_tree.items():
243 print ' BOM: %-8s VARIANTS: %s' % (
244 bom_name, ', '.join(sorted(variant_tree)))
245 for variant_code in variant_tree:
246 potential_variants.add(variant_code)
247 for volatile_code in device.volatiles:
248 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
249 if status in options.status:
250 potential_volatiles.add(volatile_code)
251 print ''
252 if len(potential_variants) == 0:
253 sys.exit('FAILURE: no matching VARIANTs found')
254 if len(potential_volatiles) == 0:
255 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
256 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700257 if (options.optimistic and
258 len(match_tree) == 1 and
259 len(potential_variants) == 1 and
260 len(potential_volatiles) == 1):
261 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
262 potential_variants.pop(),
263 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800264 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700265 print ('probing VOLATILEs to resolve potential matches: %s\n' %
266 ', '.join(sorted(potential_volatiles)))
267 vol_probe_results = Probe(
268 target_comp_classes=[],
269 probe_volatile=True,
270 probe_initial_config=False)
271 cooked_volatiles = device.MatchVolatileValues(
272 vol_probe_results.found_volatile_values)
273 match_tree = device.BuildMatchTree(
274 component_data, cooked_volatiles.matched_tags)
275 matched_hwids = device.GetMatchTreeHwids(match_tree)
276 if matched_hwids:
277 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800278 if matched_hwids[hwid] in options.status:
279 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700280 return
281 print 'exact HWID matching failed, but the following BOMs match: %s' % (
282 ', '.join(sorted(match_tree)))
283 if options.optimistic and len(match_tree) == 1:
284 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800285 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700286 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800287 if len(variant_matches) == 1:
288 var_code = set(variant_matches).pop()
289 elif len(bom.variants) == 1:
290 var_code = set(bom.variants).pop()
291 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700292 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
293 'because there were too many variants to choose from for BOM %r'
294 % bom_name)
295 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
296 for vol_code in device.volatiles
297 if device.GetHwidStatus(bom_name, var_code, vol_code)
298 in options.status]
299 for hwid in hwids:
300 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800301 return
302 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700303 print ('optimistic matching not attempted because either it was '
304 'not requested, or because the number of BOMs was <> 1\n')
305 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800306
307
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800308@Command('probe',
309 CmdArg('--comps', nargs='*',
310 help='List of keys from the component_db registry.'),
311 CmdArg('--no_vol', action='store_true',
312 help='Do not probe volatile data.'),
313 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800314 help='Do not probe initial_config data.'),
315 CmdArg('--include_vpd', action='store_true',
316 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800317def RunProbe(options):
318 """Print yaml-formatted breakdown of probed device properties."""
Tammo Spalink01e11722012-07-24 10:17:54 -0700319 probe_results = Probe(target_comp_classes=options.comps,
Jon Salz0f8a6842012-09-25 11:28:22 +0800320 probe_volatile=not options.no_vol,
321 probe_initial_config=not options.no_ic,
322 probe_vpd=options.include_vpd)
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800323 print probe_results.Encode()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800324
325
Tammo Spalink214caf42012-05-28 10:45:00 +0800326@Command('verify_components',
327 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800328 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800329def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800330 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800331
Tammo Spalink5c699832012-07-03 17:50:39 +0800332 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800333 that a corresponding match exists in the component_db -- make sure
334 that these components are present, that they have been approved, but
335 do not check against any specific BOM/HWID configurations.
336 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800337 comp_db = hwid_tool.HardwareDb(options.hwdb_path).comp_db
338 if not options.target_comps:
339 sys.exit('ERROR: no target component classes specified; possible choices:\n'
Andy Cheng228a8c92012-08-27 10:53:57 +0800340 + '\n '.join(sorted(comp_db.probeable_components)))
Tammo Spalink5c699832012-07-03 17:50:39 +0800341 for comp_class in options.target_comps:
Andy Cheng228a8c92012-08-27 10:53:57 +0800342 if comp_class not in comp_db.probeable_components:
Tammo Spalink5c699832012-07-03 17:50:39 +0800343 sys.exit('ERROR: specified component class %r does not exist'
Tammo Spalink214caf42012-05-28 10:45:00 +0800344 ' in the component DB.' % comp_class)
Tammo Spalink01e11722012-07-24 10:17:54 -0700345 probe_results = Probe(target_comp_classes=options.target_comps,
Jon Salz0f8a6842012-09-25 11:28:22 +0800346 probe_volatile=False, probe_initial_config=False)
Tammo Spalink214caf42012-05-28 10:45:00 +0800347 errors = []
348 matches = []
Tammo Spalink5c699832012-07-03 17:50:39 +0800349 for comp_class in sorted(options.target_comps):
Andy Cheng228a8c92012-08-27 10:53:57 +0800350 probe_val = probe_results.found_probe_value_map.get(comp_class, None)
Tammo Spalink214caf42012-05-28 10:45:00 +0800351 if probe_val is not None:
Tammo Spalink5c699832012-07-03 17:50:39 +0800352 comp_name = comp_db.result_name_map.get(probe_val, None)
Tammo Spalink214caf42012-05-28 10:45:00 +0800353 if comp_name is not None:
354 matches.append(comp_name)
355 else:
356 errors.append('unsupported %r component found with probe result'
357 ' %r (no matching name in the component DB)' %
358 (comp_class, probe_val))
359 else:
360 errors.append('missing %r component' % comp_class)
Andy Cheng228a8c92012-08-27 10:53:57 +0800361 if matches:
362 print 'found probeable components:\n %s' % '\n '.join(matches)
363
Tammo Spalink214caf42012-05-28 10:45:00 +0800364 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800365 print '\nerrors:\n %s' % '\n '.join(errors)
366 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800367 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800368 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800369
370
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800371@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700372 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800373 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800374 _probe_results_cmd_arg,
375 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800376def VerifyHwid(options):
377 """Verify system HWID properties match probed device properties.
378
379 First probe components, volatile and initial_config parameters for
380 the DUT. Then use the available device data to produce a list of
381 candidate HWIDs. Then verify the HWID from the DUT is present in
382 that list. Then verify that the DUT initial config values match
383 those specified for its HWID. Finally, verify that VPD contains all
384 the necessary fields as specified by the board data, and when
385 possible verify that values are legitimate.
386 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800387 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800388 for key in ro_vpd_keys:
389 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800390 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700391 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800392 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800393 if (known_valid_values is not None) and (value not in known_valid_values):
394 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800395 for key in rw_vpd_keys:
396 if key not in rw_vpd:
397 sys.exit('Missing required RW VPD field: %s' % key)
398 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
399 value = rw_vpd[key]
400 if (known_valid_values is not None) and (value not in known_valid_values):
401 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Jon Salz05aba9d2012-10-05 17:25:38 +0800402 _event_log.Log('vpd', ro_vpd=FilterVPD(ro_vpd), rw_vpd=FilterVPD(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800403 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800404
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800405 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800406
407 if options.hwid:
408 hwid_str = options.hwid
409 else:
410 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
411 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700412 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800413 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800414 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700415 device = hw_db.GetDevice(hwid.board)
416 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
417 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800418 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800419 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800420 if options.probe_results:
421 # Pull in probe results (including VPD data) from the given file
422 # rather than probing the current system.
423 probe_results = hwid_tool.ProbeResults.Decode(
424 open(options.probe_results).read())
425 ro_vpd = {}
426 rw_vpd = {}
427 for k, v in probe_results.found_volatile_values.items():
428 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
429 if match:
430 del probe_results.found_volatile_values[k]
431 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
432 else:
433 probe_results = Probe()
434 ro_vpd = ReadRoVpd(main_fw_file)
435 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700436 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
437 probe_results.found_probe_value_map)
438 cooked_volatiles = device.MatchVolatileValues(
439 probe_results.found_volatile_values)
440 cooked_initial_configs = device.MatchInitialConfigValues(
441 probe_results.initial_configs)
442 component_data = hwid_tool.ComponentData(
443 extant_components=cooked_components.matched,
444 classes_missing=probe_results.missing_component_classes)
445 match_tree = device.BuildMatchTree(
446 component_data, cooked_volatiles.matched_tags)
447 matched_hwids = device.GetMatchTreeHwids(match_tree)
448 print 'HWID status: %s\n' % hwid_status
449 print 'probed system components:'
450 print YamlWrite(cooked_components.__dict__)
451 print 'missing component classes:'
452 print YamlWrite(probe_results.missing_component_classes)
453 print 'probed volatiles:'
454 print YamlWrite(cooked_volatiles.__dict__)
455 print 'probed initial_configs:'
456 print YamlWrite(cooked_initial_configs)
457 print 'hwid match tree:'
458 print YamlWrite(match_tree)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800459 _event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800460 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700461 found_components=cooked_components.__dict__,
462 missing_component_classes=probe_results.missing_component_classes,
463 volatiles=cooked_volatiles.__dict__,
464 initial_configs=cooked_initial_configs)
465 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800466 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700467 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800468 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700469 YamlWrite(cooked_components.unmatched))
470 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800471 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700472 component_data.Encode())
473 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800474 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700475 (', '.join(sorted(match_tree)), hwid.bom))
476 err_msg += 'target bom %r matches components' % hwid.bom
477 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
478 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800479 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700480 matched_variants = match_tree.get(hwid.bom, {})
481 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800482 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700483 hwid.variant)
484 matched_volatiles = matched_variants.get(hwid.variant, {})
485 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800486 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700487 hwid.volatile)
488 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800489 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800490 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Tammo Spalink5c699832012-07-03 17:50:39 +0800491 _event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700492 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800493
494
495@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700496def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800497 """Verify keys in firmware and SSD match."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800498 script = FindScript('verify_keys.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800499 kernel_device = GetReleaseKernelPartitionPath()
500 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
501 result = Shell('%s %s %s' % (script, kernel_device, main_fw_file))
502 if not result.success:
503 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
504
505
506@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700507def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800508 """Use VPD locale value to set firmware bitmap default language."""
509 image_file = crosfw.LoadMainFirmware().GetFileName()
510 locale = ReadRoVpd(image_file).get('initial_locale', None)
511 if locale is None:
512 raise Error, 'Missing initial_locale VPD.'
513 bitmap_locales = []
514 with NamedTemporaryFile() as f:
515 Shell('gbb_utility -g --bmpfv=%s %s' % (f.name, image_file))
Tammo Spalink01e11722012-07-24 10:17:54 -0700516 bmpblk_data = unpack_bmpblock(f.read())
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800517 bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
518 # Some locale values are just a language code and others are a
519 # hyphen-separated language code and country code pair. We care
520 # only about the language code part.
521 language_code = locale.partition('-')[0]
522 if language_code not in bitmap_locales:
523 raise Error, ('Firmware bitmaps do not contain support for the specified '
524 'initial locale language %r' % language_code)
525 else:
526 locale_index = bitmap_locales.index(language_code)
527 logging.info('Firmware bitmap initial locale set to %d (%s).',
528 locale_index, bitmap_locales[locale_index])
529 Shell('crossystem loc_idx=%d' % locale_index)
530
531
532@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700533def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800534 """Verify system time is later than release filesystem creation time."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800535 script = FindScript('verify_system_time.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800536 rootfs_device = GetReleaseRootPartitionPath()
537 result = Shell('%s %s' % (script, rootfs_device))
538 if not result.success:
539 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
540
541
542@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700543def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800544 """Verify rootfs on SSD is valid by checking hash."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800545 script = FindScript('verify_rootfs.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800546 rootfs_device = GetReleaseRootPartitionPath()
547 result = Shell('%s %s' % (script, rootfs_device))
548 if not result.success:
Jon Salzb52ae702012-09-20 13:57:52 +0800549 raise Error, '%r failed, stdout: %r, stderr: %r' % (
550 script, result.stdout, result.stderr)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800551
552
553@Command('verify_switch_wp')
Tammo Spalink01e11722012-07-24 10:17:54 -0700554def VerifyWpSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800555 """Verify hardware write protection switch is enabled."""
556 if Shell('crossystem wpsw_cur').stdout.strip() != '1':
Hung-Te Lin6d827542012-07-19 11:50:41 +0800557 raise Error, 'write protection switch is disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800558
559
560@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700561def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800562 """Verify developer switch is disabled."""
Hung-Te Lind7d34722012-07-26 16:48:35 +0800563 VBSD_HONOR_VIRT_DEV_SWITCH = 0x400
564 flags = int(Shell('crossystem vdat_flags').stdout.strip(), 0)
565 if (flags & VBSD_HONOR_VIRT_DEV_SWITCH) != 0:
566 # System is using virtual developer switch. That will be handled in
567 # prepare_wipe.sh by setting "crossystem disable_dev_request=1" -- although
568 # we can't verify that until next reboot, because the real values are stored
569 # in TPM.
570 logging.warn('VerifyDevSwitch: No physical switch.')
571 _event_log.Log('switch_dev', type='virtual switch')
572 return
573 if Shell('crossystem devsw_cur').stdout.strip() != '0':
574 raise Error, 'developer mode is not disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800575
576
577@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700578def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800579 """Enable then verify firmware write protection."""
580
Hung-Te Linb21c6682012-08-01 13:53:57 +0800581 def CalculateLegacyRange(fw_type, length, section_data,
582 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800583 ro_size = length / 2
584 ro_a = int(section_data[0] / ro_size)
585 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
586 if ro_a != ro_b:
587 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800588 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800589 ro_offset = ro_a * ro_size
590 return (ro_offset, ro_size)
591
592 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800593 """Calculate protection size, then invoke flashrom.
594
595 Our supported chips only allow write protecting half their total
596 size, so we parition the flash chipset space accordingly.
597 """
598 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800599 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800600 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800601 if image.has_section(wp_section):
602 section_data = image.get_section_area(wp_section)
603 ro_offset = section_data[0]
604 ro_size = section_data[1]
605 elif image.has_section(legacy_section):
606 section_data = image.get_section_area(legacy_section)
607 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800608 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800609 else:
610 raise Error('could not find %s firmware section %s or %s' %
611 (fw_type, wp_section, legacy_section))
612
613 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
614 ro_offset, ro_size)
615 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800616
617 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800618 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800619 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
620 if ec_fw_file is not None:
621 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800622 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800623 else:
624 logging.warning('EC not write protected (seems there is no EC flash).')
625
626
627@Command('clear_gbb_flags')
Tammo Spalink01e11722012-07-24 10:17:54 -0700628def ClearGbbFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800629 """Zero out the GBB flags, in preparation for transition to release state.
630
631 No GBB flags are set in release/shipping state, but they are useful
632 for factory/development. See "gbb_utility --flags" for details.
633 """
Tammo Spalink461ddce2012-05-10 19:28:55 +0800634 script = FindScript('clear_gbb_flags.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800635 result = Shell(script)
636 if not result.success:
637 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800638 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800639
640
641@Command('prepare_wipe',
642 CmdArg('--fast', action='store_true',
643 help='use non-secure but faster wipe method.'))
644def PrepareWipe(options):
645 """Prepare system for transition to release state in next reboot."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800646 script = FindScript('prepare_wipe.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800647 tag = 'fast' if options.fast else ''
648 rootfs_device = GetReleaseRootPartitionPath()
649 result = Shell('FACTORY_WIPE_TAGS=%s %s %s' % (tag, script, rootfs_device))
650 if not result.success:
651 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
652
653
654@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800655 CmdArg('--no_write_protect', action='store_true',
656 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700657 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800658 _hwdb_path_cmd_arg,
659 _probe_results_cmd_arg,
660 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800661def Verify(options):
662 """Verifies if whole factory process is ready for finalization.
663
664 This routine performs all the necessary checks to make sure the
665 device is ready to be finalized, but does not modify state. These
666 checks include dev switch, firmware write protection switch, hwid,
667 system time, keys, and root file system.
668 """
Hung-Te Lin6d827542012-07-19 11:50:41 +0800669 if not options.no_write_protect:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800670 VerifyWpSwitch({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800671 VerifyDevSwitch({})
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800672 VerifyHwid(options)
673 VerifySystemTime({})
674 VerifyKeys({})
675 VerifyRootFs({})
676
677
Tammo Spalink86a61c62012-05-25 15:10:35 +0800678@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700679def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800680 """Write miscellaneous system details to the event log."""
681 raw_cs_data = Shell('crossystem').stdout.strip().splitlines()
682 # The crossytem output contains many lines like:
683 # 'key = value # description'
684 # Use regexps to pull out the key-value pairs and build a dict.
685 cs_data = dict((k, v.strip()) for k, v in
686 map(lambda x: re.findall(r'\A(\S+)\s+=\s+(.*)#.*\Z', x)[0],
687 raw_cs_data))
688 _event_log.Log(
689 'system_details',
690 platform_name=Shell('mosys platform name').stdout.strip(),
691 crossystem=cs_data,
692 modem_status=Shell('modem status').stdout.splitlines(),
693 ec_wp_status=Shell(
694 'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
695 'flashrom -p internal:bus=lpc --wp-status || '
696 'echo "EC is not available."').stdout,
697 bios_wp_status = Shell(
698 'flashrom -p internal:bus=spi --wp-status').stdout)
699
700
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800701_upload_method_cmd_arg = CmdArg(
702 '--upload_method', metavar='METHOD:PARAM',
703 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800704 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800705_add_file_cmd_arg = CmdArg(
706 '--add_file', metavar='FILE', action='append',
707 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800708
709@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800710 _upload_method_cmd_arg,
711 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800712def UploadReport(options):
713 """Create and a report containing key device details."""
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800714 def NormalizeAsFileName(token):
715 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800716 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
717 device_sn = ro_vpd.get('serial_number', None)
718 if device_sn is None:
719 logging.warning('RO_VPD missing device serial number')
720 device_sn = 'MISSING_SN_' + TimedUuid()
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800721 target_name = '%s_%s.tbz2' % (time.strftime('%Y%m%dT%H%M%SZ', time.gmtime()),
722 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800723 target_path = os.path.join(gettempdir(), target_name)
724 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
725 tar_cmd = 'cd %s ; tar cjf %s *' % (EVENT_LOG_DIR, target_path)
726 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800727 if options.add_file:
728 for f in options.add_file:
729 # Require absolute paths since the tar command may change the
730 # directory.
731 if not f.startswith('/'):
732 raise Error('Not an absolute path: %s' % f)
733 if not os.path.exists(f):
734 raise Error('File does not exist: %s' % f)
735 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800736 cmd_result = Shell(tar_cmd)
737 if not cmd_result.success:
738 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
739 (tar_cmd, cmd_result.stderr))
740 if options.upload_method is None or options.upload_method == 'none':
741 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
742 return
743 method, param = options.upload_method.split(':', 1)
744 if method == 'shopfloor':
745 report_upload.ShopFloorUpload(target_path, param)
746 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700747 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800748 elif method == 'ftps':
749 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
750 elif method == 'cpfe':
751 report_upload.CpfeUpload(target_path, param)
752 else:
753 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800754
755
756@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800757 CmdArg('--no_write_protect', action='store_true',
758 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800759 CmdArg('--fast', action='store_true',
760 help='use non-secure but faster wipe method.'),
761 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700762 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800763 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800764 _add_file_cmd_arg,
765 _probe_results_cmd_arg,
766 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800767def Finalize(options):
768 """Verify system readiness and trigger transition into release state.
769
Hung-Te Lin6d827542012-07-19 11:50:41 +0800770 This routine first verifies system state (see verify command), modifies
771 firmware bitmaps to match locale, and then clears all of the factory-friendly
772 flags from the GBB. If everything is fine, it enables firmware write
773 protection (cannot rollback after this stage), uploads system logs & reports,
774 and sets the necessary boot flags to cause wipe of the factory image on the
775 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800776 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800777 Verify(options)
778 SetFirmwareBitmapLocale({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800779 ClearGbbFlags({})
780 if options.no_write_protect:
781 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
782 _event_log.Log('wp', fw='both', status='skipped')
783 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800784 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800785 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800786 UploadReport(options)
787 PrepareWipe(options)
788
789
790def Main():
791 """Run sub-command specified by the command line args."""
792 options = ParseCmdline(
793 'Perform Google required factory tests.',
794 CmdArg('-l', '--log', metavar='PATH',
795 help='Write logs to this file.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800796 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800797 SetupLogging(options.verbosity, options.log)
798 logging.debug('gooftool options: %s', repr(options))
799 try:
800 logging.debug('GOOFTOOL command %r', options.command_name)
801 options.command(options)
802 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
803 except Error, e:
804 logging.exception(e)
805 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
806 except Exception, e:
807 logging.exception(e)
808 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
809
810
811if __name__ == '__main__':
812 Main()