blob: fad11e5a0f6416865b0363a44f99782145c6b5cc [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
Tammo Spalink01e11722012-07-24 10:17:54 -070034from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
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
117
Tammo Spalink95c43732012-07-25 15:57:14 -0700118_hwid_status_list_cmd_arg = CmdArg(
119 '--status', nargs='*', default=['supported'],
120 help='allow only HWIDs with these status values')
121
122
123@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800124 _hwdb_path_cmd_arg,
125 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700126 help='optional BOARD name, needed only if data is present '
127 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800128 CmdArg('--bom', metavar='BOM', help='BOM name'),
129 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800130 CmdArg('--optimistic', action='store_true',
131 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700132 CmdArg('--comps', nargs='*', default=[],
133 help='list of canonical component names'),
134 CmdArg('--missing', nargs='*', default=[],
135 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800136 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700137 help='consider only HWIDs within this list of status values'))
138def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800139 """Determine a list of possible HWIDs using provided args and probeing.
140
141 VOLATILE can always be determined by probing. To get a unique
142 result, VARIANT must be specified for all cases where the matching
143 BOM has more than one associated variant code, otherwise all HWID
144 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700145 alternatively be specified using the --stdin_comps argument, which
146 allows specifying a list of canonical names (one per line) on stdin,
147 one per line. Based on what is known from BOM and stdin_comps,
148 determine a list of components to probe for, and use those probe
149 results to resolve a list of matching HWIDs. If no boms,
150 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800151 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800152
153 Returns (on stdout): A list of HWIDs that match the available probe
154 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700155
156 Example:
157
158 // Three ways to specify a keyboard (assuming it is a variant component)
159 gooftool best_match_hwids --missing keyboard
160 gooftool best_match_hwids --variant A or
161 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800162 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800163 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700164 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800165 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800166 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800167 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800168 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800169 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700170 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800171 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800172 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800173 device.VariantExists(options.variant)
174 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700175 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700176 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700177 % YamlWrite(sorted(
178 hwid_tool.ComponentSpecClasses(component_spec) &
179 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700180 component_spec = hwid_tool.CombineComponentSpecs(
181 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700182 if options.comps or options.missing:
183 map(comp_db.CompExists, options.comps)
184 map(comp_db.CompClassExists, options.missing)
185 extra_comp_spec = comp_db.CreateComponentSpec(
186 components=options.comps,
187 missing=options.missing)
188 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
189 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
190 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700191 % YamlWrite(sorted(
192 hwid_tool.ComponentSpecClasses(component_spec) &
193 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700194 component_spec = hwid_tool.CombineComponentSpecs(
195 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700196 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700197 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800198 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800199 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
200 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700201 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700202 'as inputs, and cannot be probed for:\n%s'
203 'This problem can often be addressed by specifying all of '
204 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800205 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700206 print 'probing for missing classes:'
207 print YamlWrite(list(missing_classes))
208 probe_results = Probe(target_comp_classes=list(missing_classes),
209 probe_volatile=False, probe_initial_config=False)
210 cooked_components = comp_db.MatchComponentProbeValues(
211 probe_results.found_probe_value_map)
212 if cooked_components.unmatched:
213 sys.exit('ERROR: some probed components are unrecognized:\n%s'
214 % YamlWrite(cooked_components.unmatched))
215 probed_comp_spec = comp_db.CreateComponentSpec(
216 components=cooked_components.matched,
217 missing=probe_results.missing_component_classes)
218 component_spec = hwid_tool.CombineComponentSpecs(
219 component_spec, probed_comp_spec)
220 print YamlWrite({'component data used for matching': {
221 'missing component classes': component_spec.classes_missing,
222 'found components': component_spec.components}})
223 component_data = hwid_tool.ComponentData(
224 extant_components=hwid_tool.ComponentSpecCompClassMap(
225 component_spec).keys(),
226 classes_missing=component_spec.classes_missing)
227 match_tree = device.BuildMatchTree(component_data)
228 if not match_tree:
229 sys.exit('FAILURE: NO matching BOMs found')
230 print 'potential BOMs/VARIANTs:'
231 potential_variants = set()
232 potential_volatiles = set()
233 for bom_name, variant_tree in match_tree.items():
234 print ' BOM: %-8s VARIANTS: %s' % (
235 bom_name, ', '.join(sorted(variant_tree)))
236 for variant_code in variant_tree:
237 potential_variants.add(variant_code)
238 for volatile_code in device.volatiles:
239 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
240 if status in options.status:
241 potential_volatiles.add(volatile_code)
242 print ''
243 if len(potential_variants) == 0:
244 sys.exit('FAILURE: no matching VARIANTs found')
245 if len(potential_volatiles) == 0:
246 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
247 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700248 if (options.optimistic and
249 len(match_tree) == 1 and
250 len(potential_variants) == 1 and
251 len(potential_volatiles) == 1):
252 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
253 potential_variants.pop(),
254 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800255 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700256 print ('probing VOLATILEs to resolve potential matches: %s\n' %
257 ', '.join(sorted(potential_volatiles)))
258 vol_probe_results = Probe(
259 target_comp_classes=[],
260 probe_volatile=True,
261 probe_initial_config=False)
262 cooked_volatiles = device.MatchVolatileValues(
263 vol_probe_results.found_volatile_values)
264 match_tree = device.BuildMatchTree(
265 component_data, cooked_volatiles.matched_tags)
266 matched_hwids = device.GetMatchTreeHwids(match_tree)
267 if matched_hwids:
268 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800269 if matched_hwids[hwid] in options.status:
270 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700271 return
272 print 'exact HWID matching failed, but the following BOMs match: %s' % (
273 ', '.join(sorted(match_tree)))
274 if options.optimistic and len(match_tree) == 1:
275 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800276 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700277 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800278 if len(variant_matches) == 1:
279 var_code = set(variant_matches).pop()
280 elif len(bom.variants) == 1:
281 var_code = set(bom.variants).pop()
282 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700283 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
284 'because there were too many variants to choose from for BOM %r'
285 % bom_name)
286 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
287 for vol_code in device.volatiles
288 if device.GetHwidStatus(bom_name, var_code, vol_code)
289 in options.status]
290 for hwid in hwids:
291 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800292 return
293 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700294 print ('optimistic matching not attempted because either it was '
295 'not requested, or because the number of BOMs was <> 1\n')
296 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800297
298
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800299@Command('probe',
300 CmdArg('--comps', nargs='*',
301 help='List of keys from the component_db registry.'),
302 CmdArg('--no_vol', action='store_true',
303 help='Do not probe volatile data.'),
304 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800305 help='Do not probe initial_config data.'),
306 CmdArg('--include_vpd', action='store_true',
307 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800308def RunProbe(options):
309 """Print yaml-formatted breakdown of probed device properties."""
Tammo Spalink01e11722012-07-24 10:17:54 -0700310 probe_results = Probe(target_comp_classes=options.comps,
Jon Salz0f8a6842012-09-25 11:28:22 +0800311 probe_volatile=not options.no_vol,
312 probe_initial_config=not options.no_ic,
313 probe_vpd=options.include_vpd)
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800314 print probe_results.Encode()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800315
316
Tammo Spalink214caf42012-05-28 10:45:00 +0800317@Command('verify_components',
318 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800319 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800320def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800321 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800322
Tammo Spalink5c699832012-07-03 17:50:39 +0800323 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800324 that a corresponding match exists in the component_db -- make sure
325 that these components are present, that they have been approved, but
326 do not check against any specific BOM/HWID configurations.
327 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800328 comp_db = hwid_tool.HardwareDb(options.hwdb_path).comp_db
329 if not options.target_comps:
330 sys.exit('ERROR: no target component classes specified; possible choices:\n'
Andy Cheng228a8c92012-08-27 10:53:57 +0800331 + '\n '.join(sorted(comp_db.probeable_components)))
Tammo Spalink5c699832012-07-03 17:50:39 +0800332 for comp_class in options.target_comps:
Andy Cheng228a8c92012-08-27 10:53:57 +0800333 if comp_class not in comp_db.probeable_components:
Tammo Spalink5c699832012-07-03 17:50:39 +0800334 sys.exit('ERROR: specified component class %r does not exist'
Tammo Spalink214caf42012-05-28 10:45:00 +0800335 ' in the component DB.' % comp_class)
Tammo Spalink01e11722012-07-24 10:17:54 -0700336 probe_results = Probe(target_comp_classes=options.target_comps,
Jon Salz0f8a6842012-09-25 11:28:22 +0800337 probe_volatile=False, probe_initial_config=False)
Tammo Spalink214caf42012-05-28 10:45:00 +0800338 errors = []
339 matches = []
Tammo Spalink5c699832012-07-03 17:50:39 +0800340 for comp_class in sorted(options.target_comps):
Andy Cheng228a8c92012-08-27 10:53:57 +0800341 probe_val = probe_results.found_probe_value_map.get(comp_class, None)
Tammo Spalink214caf42012-05-28 10:45:00 +0800342 if probe_val is not None:
Tammo Spalink5c699832012-07-03 17:50:39 +0800343 comp_name = comp_db.result_name_map.get(probe_val, None)
Tammo Spalink214caf42012-05-28 10:45:00 +0800344 if comp_name is not None:
345 matches.append(comp_name)
346 else:
347 errors.append('unsupported %r component found with probe result'
348 ' %r (no matching name in the component DB)' %
349 (comp_class, probe_val))
350 else:
351 errors.append('missing %r component' % comp_class)
Andy Cheng228a8c92012-08-27 10:53:57 +0800352 if matches:
353 print 'found probeable components:\n %s' % '\n '.join(matches)
354
Tammo Spalink214caf42012-05-28 10:45:00 +0800355 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800356 print '\nerrors:\n %s' % '\n '.join(errors)
357 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800358 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800359 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800360
361
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800362@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700363 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800364 _hwdb_path_cmd_arg,
365 CmdArg('--probe_results', metavar='RESULTS.yaml',
366 help=('Output from "gooftool probe" (used instead of '
367 'probing this system).')),
368 CmdArg('--hwid', metavar='HWID',
369 help=('HWID to verify (instead of the currently set HWID of '
370 'this system)')))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800371def VerifyHwid(options):
372 """Verify system HWID properties match probed device properties.
373
374 First probe components, volatile and initial_config parameters for
375 the DUT. Then use the available device data to produce a list of
376 candidate HWIDs. Then verify the HWID from the DUT is present in
377 that list. Then verify that the DUT initial config values match
378 those specified for its HWID. Finally, verify that VPD contains all
379 the necessary fields as specified by the board data, and when
380 possible verify that values are legitimate.
381 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800382 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800383 for key in ro_vpd_keys:
384 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800385 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700386 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800387 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800388 if (known_valid_values is not None) and (value not in known_valid_values):
389 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800390 for key in rw_vpd_keys:
391 if key not in rw_vpd:
392 sys.exit('Missing required RW VPD field: %s' % key)
393 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
394 value = rw_vpd[key]
395 if (known_valid_values is not None) and (value not in known_valid_values):
396 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Tammo Spalink5c699832012-07-03 17:50:39 +0800397 _event_log.Log('vpd', ro_vpd=ro_vpd, rw_vpd=rw_vpd)
398 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800399
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800400 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800401
402 if options.hwid:
403 hwid_str = options.hwid
404 else:
405 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
406 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700407 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800408 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800409 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700410 device = hw_db.GetDevice(hwid.board)
411 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
412 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800413 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800414 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800415 if options.probe_results:
416 # Pull in probe results (including VPD data) from the given file
417 # rather than probing the current system.
418 probe_results = hwid_tool.ProbeResults.Decode(
419 open(options.probe_results).read())
420 ro_vpd = {}
421 rw_vpd = {}
422 for k, v in probe_results.found_volatile_values.items():
423 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
424 if match:
425 del probe_results.found_volatile_values[k]
426 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
427 else:
428 probe_results = Probe()
429 ro_vpd = ReadRoVpd(main_fw_file)
430 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700431 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
432 probe_results.found_probe_value_map)
433 cooked_volatiles = device.MatchVolatileValues(
434 probe_results.found_volatile_values)
435 cooked_initial_configs = device.MatchInitialConfigValues(
436 probe_results.initial_configs)
437 component_data = hwid_tool.ComponentData(
438 extant_components=cooked_components.matched,
439 classes_missing=probe_results.missing_component_classes)
440 match_tree = device.BuildMatchTree(
441 component_data, cooked_volatiles.matched_tags)
442 matched_hwids = device.GetMatchTreeHwids(match_tree)
443 print 'HWID status: %s\n' % hwid_status
444 print 'probed system components:'
445 print YamlWrite(cooked_components.__dict__)
446 print 'missing component classes:'
447 print YamlWrite(probe_results.missing_component_classes)
448 print 'probed volatiles:'
449 print YamlWrite(cooked_volatiles.__dict__)
450 print 'probed initial_configs:'
451 print YamlWrite(cooked_initial_configs)
452 print 'hwid match tree:'
453 print YamlWrite(match_tree)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800454 _event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800455 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700456 found_components=cooked_components.__dict__,
457 missing_component_classes=probe_results.missing_component_classes,
458 volatiles=cooked_volatiles.__dict__,
459 initial_configs=cooked_initial_configs)
460 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800461 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700462 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800463 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700464 YamlWrite(cooked_components.unmatched))
465 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800466 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700467 component_data.Encode())
468 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700470 (', '.join(sorted(match_tree)), hwid.bom))
471 err_msg += 'target bom %r matches components' % hwid.bom
472 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
473 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800474 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700475 matched_variants = match_tree.get(hwid.bom, {})
476 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800477 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700478 hwid.variant)
479 matched_volatiles = matched_variants.get(hwid.variant, {})
480 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800481 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700482 hwid.volatile)
483 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800484 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800485 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Tammo Spalink5c699832012-07-03 17:50:39 +0800486 _event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700487 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800488
489
490@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700491def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800492 """Verify keys in firmware and SSD match."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800493 script = FindScript('verify_keys.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800494 kernel_device = GetReleaseKernelPartitionPath()
495 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
496 result = Shell('%s %s %s' % (script, kernel_device, main_fw_file))
497 if not result.success:
498 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
499
500
501@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700502def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503 """Use VPD locale value to set firmware bitmap default language."""
504 image_file = crosfw.LoadMainFirmware().GetFileName()
505 locale = ReadRoVpd(image_file).get('initial_locale', None)
506 if locale is None:
507 raise Error, 'Missing initial_locale VPD.'
508 bitmap_locales = []
509 with NamedTemporaryFile() as f:
510 Shell('gbb_utility -g --bmpfv=%s %s' % (f.name, image_file))
Tammo Spalink01e11722012-07-24 10:17:54 -0700511 bmpblk_data = unpack_bmpblock(f.read())
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800512 bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
513 # Some locale values are just a language code and others are a
514 # hyphen-separated language code and country code pair. We care
515 # only about the language code part.
516 language_code = locale.partition('-')[0]
517 if language_code not in bitmap_locales:
518 raise Error, ('Firmware bitmaps do not contain support for the specified '
519 'initial locale language %r' % language_code)
520 else:
521 locale_index = bitmap_locales.index(language_code)
522 logging.info('Firmware bitmap initial locale set to %d (%s).',
523 locale_index, bitmap_locales[locale_index])
524 Shell('crossystem loc_idx=%d' % locale_index)
525
526
527@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700528def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800529 """Verify system time is later than release filesystem creation time."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800530 script = FindScript('verify_system_time.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800531 rootfs_device = GetReleaseRootPartitionPath()
532 result = Shell('%s %s' % (script, rootfs_device))
533 if not result.success:
534 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
535
536
537@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700538def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800539 """Verify rootfs on SSD is valid by checking hash."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800540 script = FindScript('verify_rootfs.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800541 rootfs_device = GetReleaseRootPartitionPath()
542 result = Shell('%s %s' % (script, rootfs_device))
543 if not result.success:
Jon Salzb52ae702012-09-20 13:57:52 +0800544 raise Error, '%r failed, stdout: %r, stderr: %r' % (
545 script, result.stdout, result.stderr)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800546
547
548@Command('verify_switch_wp')
Tammo Spalink01e11722012-07-24 10:17:54 -0700549def VerifyWpSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800550 """Verify hardware write protection switch is enabled."""
551 if Shell('crossystem wpsw_cur').stdout.strip() != '1':
Hung-Te Lin6d827542012-07-19 11:50:41 +0800552 raise Error, 'write protection switch is disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800553
554
555@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700556def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800557 """Verify developer switch is disabled."""
Hung-Te Lind7d34722012-07-26 16:48:35 +0800558 VBSD_HONOR_VIRT_DEV_SWITCH = 0x400
559 flags = int(Shell('crossystem vdat_flags').stdout.strip(), 0)
560 if (flags & VBSD_HONOR_VIRT_DEV_SWITCH) != 0:
561 # System is using virtual developer switch. That will be handled in
562 # prepare_wipe.sh by setting "crossystem disable_dev_request=1" -- although
563 # we can't verify that until next reboot, because the real values are stored
564 # in TPM.
565 logging.warn('VerifyDevSwitch: No physical switch.')
566 _event_log.Log('switch_dev', type='virtual switch')
567 return
568 if Shell('crossystem devsw_cur').stdout.strip() != '0':
569 raise Error, 'developer mode is not disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800570
571
572@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700573def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800574 """Enable then verify firmware write protection."""
575
Hung-Te Linb21c6682012-08-01 13:53:57 +0800576 def CalculateLegacyRange(fw_type, length, section_data,
577 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800578 ro_size = length / 2
579 ro_a = int(section_data[0] / ro_size)
580 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
581 if ro_a != ro_b:
582 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800583 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800584 ro_offset = ro_a * ro_size
585 return (ro_offset, ro_size)
586
587 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800588 """Calculate protection size, then invoke flashrom.
589
590 Our supported chips only allow write protecting half their total
591 size, so we parition the flash chipset space accordingly.
592 """
593 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800594 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800595 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800596 if image.has_section(wp_section):
597 section_data = image.get_section_area(wp_section)
598 ro_offset = section_data[0]
599 ro_size = section_data[1]
600 elif image.has_section(legacy_section):
601 section_data = image.get_section_area(legacy_section)
602 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800603 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800604 else:
605 raise Error('could not find %s firmware section %s or %s' %
606 (fw_type, wp_section, legacy_section))
607
608 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
609 ro_offset, ro_size)
610 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800611
612 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800613 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800614 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
615 if ec_fw_file is not None:
616 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800617 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800618 else:
619 logging.warning('EC not write protected (seems there is no EC flash).')
620
621
622@Command('clear_gbb_flags')
Tammo Spalink01e11722012-07-24 10:17:54 -0700623def ClearGbbFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800624 """Zero out the GBB flags, in preparation for transition to release state.
625
626 No GBB flags are set in release/shipping state, but they are useful
627 for factory/development. See "gbb_utility --flags" for details.
628 """
Tammo Spalink461ddce2012-05-10 19:28:55 +0800629 script = FindScript('clear_gbb_flags.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800630 result = Shell(script)
631 if not result.success:
632 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800633 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800634
635
636@Command('prepare_wipe',
637 CmdArg('--fast', action='store_true',
638 help='use non-secure but faster wipe method.'))
639def PrepareWipe(options):
640 """Prepare system for transition to release state in next reboot."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800641 script = FindScript('prepare_wipe.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800642 tag = 'fast' if options.fast else ''
643 rootfs_device = GetReleaseRootPartitionPath()
644 result = Shell('FACTORY_WIPE_TAGS=%s %s %s' % (tag, script, rootfs_device))
645 if not result.success:
646 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
647
648
649@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800650 CmdArg('--no_write_protect', action='store_true',
651 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700652 _hwid_status_list_cmd_arg,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800653 _hwdb_path_cmd_arg)
654def Verify(options):
655 """Verifies if whole factory process is ready for finalization.
656
657 This routine performs all the necessary checks to make sure the
658 device is ready to be finalized, but does not modify state. These
659 checks include dev switch, firmware write protection switch, hwid,
660 system time, keys, and root file system.
661 """
Hung-Te Lin6d827542012-07-19 11:50:41 +0800662 if not options.no_write_protect:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800663 VerifyWpSwitch({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800664 VerifyDevSwitch({})
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800665 VerifyHwid(options)
666 VerifySystemTime({})
667 VerifyKeys({})
668 VerifyRootFs({})
669
670
Tammo Spalink86a61c62012-05-25 15:10:35 +0800671@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700672def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800673 """Write miscellaneous system details to the event log."""
674 raw_cs_data = Shell('crossystem').stdout.strip().splitlines()
675 # The crossytem output contains many lines like:
676 # 'key = value # description'
677 # Use regexps to pull out the key-value pairs and build a dict.
678 cs_data = dict((k, v.strip()) for k, v in
679 map(lambda x: re.findall(r'\A(\S+)\s+=\s+(.*)#.*\Z', x)[0],
680 raw_cs_data))
681 _event_log.Log(
682 'system_details',
683 platform_name=Shell('mosys platform name').stdout.strip(),
684 crossystem=cs_data,
685 modem_status=Shell('modem status').stdout.splitlines(),
686 ec_wp_status=Shell(
687 'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
688 'flashrom -p internal:bus=lpc --wp-status || '
689 'echo "EC is not available."').stdout,
690 bios_wp_status = Shell(
691 'flashrom -p internal:bus=spi --wp-status').stdout)
692
693
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800694_upload_method_cmd_arg = CmdArg(
695 '--upload_method', metavar='METHOD:PARAM',
696 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800697 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800698_add_file_cmd_arg = CmdArg(
699 '--add_file', metavar='FILE', action='append',
700 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800701
702@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800703 _upload_method_cmd_arg,
704 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800705def UploadReport(options):
706 """Create and a report containing key device details."""
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800707 def NormalizeAsFileName(token):
708 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800709 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
710 device_sn = ro_vpd.get('serial_number', None)
711 if device_sn is None:
712 logging.warning('RO_VPD missing device serial number')
713 device_sn = 'MISSING_SN_' + TimedUuid()
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800714 target_name = '%s_%s.tbz2' % (time.strftime('%Y%m%dT%H%M%SZ', time.gmtime()),
715 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800716 target_path = os.path.join(gettempdir(), target_name)
717 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
718 tar_cmd = 'cd %s ; tar cjf %s *' % (EVENT_LOG_DIR, target_path)
719 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800720 if options.add_file:
721 for f in options.add_file:
722 # Require absolute paths since the tar command may change the
723 # directory.
724 if not f.startswith('/'):
725 raise Error('Not an absolute path: %s' % f)
726 if not os.path.exists(f):
727 raise Error('File does not exist: %s' % f)
728 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800729 cmd_result = Shell(tar_cmd)
730 if not cmd_result.success:
731 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
732 (tar_cmd, cmd_result.stderr))
733 if options.upload_method is None or options.upload_method == 'none':
734 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
735 return
736 method, param = options.upload_method.split(':', 1)
737 if method == 'shopfloor':
738 report_upload.ShopFloorUpload(target_path, param)
739 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700740 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800741 elif method == 'ftps':
742 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
743 elif method == 'cpfe':
744 report_upload.CpfeUpload(target_path, param)
745 else:
746 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800747
748
749@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800750 CmdArg('--no_write_protect', action='store_true',
751 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800752 CmdArg('--fast', action='store_true',
753 help='use non-secure but faster wipe method.'),
754 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700755 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800756 _upload_method_cmd_arg,
757 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800758def Finalize(options):
759 """Verify system readiness and trigger transition into release state.
760
Hung-Te Lin6d827542012-07-19 11:50:41 +0800761 This routine first verifies system state (see verify command), modifies
762 firmware bitmaps to match locale, and then clears all of the factory-friendly
763 flags from the GBB. If everything is fine, it enables firmware write
764 protection (cannot rollback after this stage), uploads system logs & reports,
765 and sets the necessary boot flags to cause wipe of the factory image on the
766 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800767 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800768 Verify(options)
769 SetFirmwareBitmapLocale({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800770 ClearGbbFlags({})
771 if options.no_write_protect:
772 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
773 _event_log.Log('wp', fw='both', status='skipped')
774 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800775 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800776 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800777 UploadReport(options)
778 PrepareWipe(options)
779
780
781def Main():
782 """Run sub-command specified by the command line args."""
783 options = ParseCmdline(
784 'Perform Google required factory tests.',
785 CmdArg('-l', '--log', metavar='PATH',
786 help='Write logs to this file.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800787 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800788 SetupLogging(options.verbosity, options.log)
789 logging.debug('gooftool options: %s', repr(options))
790 try:
791 logging.debug('GOOFTOOL command %r', options.command_name)
792 options.command(options)
793 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
794 except Error, e:
795 logging.exception(e)
796 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
797 except Exception, e:
798 logging.exception(e)
799 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
800
801
802if __name__ == '__main__':
803 Main()