blob: 7b79b23283c65efc46491085be23996205bbbc01 [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
2#
3# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Google Factory Tool.
8
9This tool is indended to be used on factory assembly lines. It
10provides all of the Google required test functionality and must be run
11on each device as part of the assembly process.
12"""
13
14
15import logging
16import os
17import re
18import sys
19
Tammo Spalink8fab5312012-05-28 18:33:30 +080020from tempfile import gettempdir, NamedTemporaryFile
Tammo Spalink86a61c62012-05-25 15:10:35 +080021
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080022import bmpblk
23import crosfw
24import hwid_tool
25import probe
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080026import report_upload
27import vpd_data
28
Tammo Spalink8fab5312012-05-28 18:33:30 +080029from common import Error, ParseKeyValueData, SetupLogging, Shell
30from common import YamlRead, YamlWrite
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080031from hacked_argparse import CmdArg, Command, ParseCmdline, verbosity_cmd_arg
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080032
Tammo Spalink86a61c62012-05-25 15:10:35 +080033# TODO(tammo): Remove imp logic once the cros/factory code moves into this repo.
Tammo Spalink8fab5312012-05-28 18:33:30 +080034# NOTE: These imports also corrupt the python logging module...
Tammo Spalink86a61c62012-05-25 15:10:35 +080035import imp
36at_common = imp.find_module('common', ['/usr/local/autotest/client/bin'])
37imp.load_module('at_common', *at_common)
38from autotest_lib.client.cros.factory.event_log import EventLog, EVENT_LOG_DIR
39from autotest_lib.client.cros.factory.event_log import TimeString, TimedUuid
40from autotest_lib.client.cros.factory import FACTORY_LOG_PATH
41
42
43# 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):
Jon Salzd24269c2012-05-29 17:22:59 +080084 script_path = os.path.join(os.path.dirname(os.path.dirname(
85 os.path.realpath(__file__))), 'sh', script_name)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080086 if not os.path.exists(script_path):
87 raise Error('Needed script %s does not exist.' % script_path)
88 return script_path
89
90
Tammo Spalink86a61c62012-05-25 15:10:35 +080091def ReadVpd(fw_image_file, kind):
92 raw_vpd_data = Shell('vpd -i %s -l -f %s' % (kind, fw_image_file)).stdout
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080093 return ParseKeyValueData('"(.*)"="(.*)"$', raw_vpd_data)
94
95
Tammo Spalink86a61c62012-05-25 15:10:35 +080096def ReadRoVpd(fw_image_file):
97 return ReadVpd(fw_image_file, 'RO_VPD')
98
99
100def ReadRwVpd(fw_image_file):
101 return ReadVpd(fw_image_file, 'RW_VPD')
102
103
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800104@Command('write_hwid',
105 CmdArg('hwid', metavar='HWID', help='HWID string'))
106def WriteHwid(options):
107 """Write specified HWID value into the system BB."""
108 logging.debug('writing hwid string %r', options.hwid)
109 main_fw = crosfw.LoadMainFirmware()
110 Shell('gbb_utility --set --hwid="%s" "%s"' %
111 (options.hwid, main_fw.GetFileName()))
112 main_fw.Write(sections=['GBB'])
Tammo Spalink86a61c62012-05-25 15:10:35 +0800113 _event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800114
115
Tammo Spalink8fab5312012-05-28 18:33:30 +0800116_hwdb_path_cmd_arg = CmdArg(
117 '--hwdb_path', metavar='PATH',
118 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
119 help='Path to the HWID database.')
120
121
122@Command('probe_hwids',
123 _hwdb_path_cmd_arg,
124 CmdArg('-b', '--board', metavar='BOARD',
125 help='BOARD name', required=True),
126 CmdArg('--bom', metavar='BOM', help='BOM name'),
127 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
128 CmdArg('--comp_map', action='store_true'),
129 CmdArg('--status', nargs='*',
130 help='consider only HWIDs with this status'))
131def ProbeHwid(options):
132 """Determine a list of possible HWIDs using provided args and probeing.
133
134 VOLATILE can always be determined by probing. To get a unique
135 result, VARIANT must be specified for all cases where the matching
136 BOM has more than one associated variant code, otherwise all HWID
137 variants will be returned. Both VARIANT and BOM information can
138 alternatively be specified using the --comp_map argument, which
139 allows specifying a list of
140
141 component-class: canonical-component-name
142
143 pairs on stdin, one per line (yaml format). Based on what is known
144 from BOM and comp_map, determine a list of components to probe for,
145 and use those probe results to resolve a list of matching HWIDs. If
146 no boms, components, or variant codes are specified, then a list of
147 all HWIDs that match probable components will be returned.
148
149 Returns (on stdout): A list of HWIDs that match the available probe
150 results and argument contraints, one per line.
151 """
152 hwdb = hwid_tool.ReadDatastore(options.hwdb_path)
153 if options.board not in hwdb.device_db:
154 sys.exit('ERROR: unknown board %r' % options.board)
155 device = hwdb.device_db[options.board]
156 component_map = {}
157 if options.bom:
158 bom_details = device.hwid_map.get(options.bom, None)
159 if bom_details is None:
160 sys.exit('ERROR: unkown bom %r for board %r' %
161 (options.bom, options.board))
162 component_map.update(bom_details.component_map)
163 comp_db_class_map = hwid_tool.CalcCompDbClassMap(hwdb.comp_db)
164 if options.variant:
165 variant_details = device.variant_map.get(options.variant, None)
166 if options.variant is None:
167 sys.exit('ERROR: unknown variant code %r for board %r' %
168 (options.variant, options.board))
169 for comp_name in variant_details:
170 comp_class = comp_db_class_map[comp_name]
171 if comp_class in component_map:
172 sys.exit('ERROR: multiple specifications for %r components'
173 ' (both VARIANT and BOM)' % comp_class)
174 component_map[comp_class] = comp_name
175 if options.comp_map:
176 input_map = YamlRead(sys.stdin.read())
177 logging.info('stdin component map: %r', input_map)
178 for key, value in input_map.items():
179 if key not in hwdb.comp_db.registry:
180 sys.exit('ERROR: unknown component class %r (from stdin)' % key)
181 if value not in comp_db_class_map:
182 sys.exit('ERROR: unkown component name %r (from stdin)' % value)
183 if key in component_map:
184 sys.exit('ERROR: multiple specifications for %r components'
185 ' (stdin and BOM/VARIANT)' % key)
186 component_map[key] = value
187 missing_classes = list(set(hwdb.comp_db.registry) - set(component_map))
188 if missing_classes:
189 logging.info('probing for %s', ', '.join(missing_classes))
190 probe_results = probe.Probe(target_comp_classes=missing_classes,
191 probe_volatile=True, probe_initial_config=False)
192 cooked_results = hwid_tool.CookProbeResults(
193 hwdb, probe_results, options.board)
194 cooked_results.matched_components.update(component_map)
195 status_set = set(options.status) if options.status else set(['supported'])
196 hwid_set = hwid_tool.MatchHwids(hwdb, cooked_results, options.board,
197 status_set)
198 if not hwid_set:
199 sys.exit('NO matching HWIDs found')
200 print '\n'.join(hwid_set)
201
202
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800203@Command('probe',
204 CmdArg('--comps', nargs='*',
205 help='List of keys from the component_db registry.'),
206 CmdArg('--no_vol', action='store_true',
207 help='Do not probe volatile data.'),
208 CmdArg('--no_ic', action='store_true',
209 help='Do not probe initial_config data.'))
210def RunProbe(options):
211 """Print yaml-formatted breakdown of probed device properties."""
212 probe_results = probe.Probe(target_comp_classes=options.comps,
213 probe_volatile=not options.no_vol,
214 probe_initial_config=not options.no_ic)
215 print YamlWrite(probe_results.__dict__)
216
217
Tammo Spalink214caf42012-05-28 10:45:00 +0800218@Command('verify_components',
219 _hwdb_path_cmd_arg,
220 CmdArg('comp_white_list', nargs='*'))
221def VerifyComponents(options):
222 """Verify that probable components all match entries in the component_db.
223
224 Probe for each component class in the comp_white_list and verify
225 that a corresponding match exists in the component_db -- make sure
226 that these components are present, that they have been approved, but
227 do not check against any specific BOM/HWID configurations.
228 """
229 hwdb = hwid_tool.ReadDatastore(options.hwdb_path)
230 if not options.comp_white_list:
231 sys.exit('ERROR: no component white list specified; possible choices:\n %s'
232 % '\n '.join(sorted(hwdb.comp_db.registry)))
233 for comp_class in options.comp_white_list:
234 if comp_class not in hwdb.comp_db.registry:
235 sys.exit('ERROR: specified white list component class %r does not exist'
236 ' in the component DB.' % comp_class)
237 probe_results = probe.Probe(target_comp_classes=options.comp_white_list,
238 probe_volatile=False, probe_initial_config=False)
239 probe_val_map = hwid_tool.CalcCompDbProbeValMap(hwdb.comp_db)
240 errors = []
241 matches = []
242 for comp_class in sorted(options.comp_white_list):
243 probe_val = probe_results.found_components.get(comp_class, None)
244 if probe_val is not None:
245 comp_name = probe_val_map.get(probe_val, None)
246 if comp_name is not None:
247 matches.append(comp_name)
248 else:
249 errors.append('unsupported %r component found with probe result'
250 ' %r (no matching name in the component DB)' %
251 (comp_class, probe_val))
252 else:
253 errors.append('missing %r component' % comp_class)
254 if errors:
255 print '\n'.join(errors)
256 sys.exit('component verification FAILURE')
257 else:
258 print 'component verification SUCCESS'
259 print 'found components:\n %s' % '\n '.join(matches)
260
261
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800262@Command('verify_hwid',
263 _hwdb_path_cmd_arg)
264def VerifyHwid(options):
265 """Verify system HWID properties match probed device properties.
266
267 First probe components, volatile and initial_config parameters for
268 the DUT. Then use the available device data to produce a list of
269 candidate HWIDs. Then verify the HWID from the DUT is present in
270 that list. Then verify that the DUT initial config values match
271 those specified for its HWID. Finally, verify that VPD contains all
272 the necessary fields as specified by the board data, and when
273 possible verify that values are legitimate.
274 """
275 hwdb = hwid_tool.ReadDatastore(options.hwdb_path)
276 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
277 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
278 hwid = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
279 hwid_properties = hwid_tool.LookupHwidProperties(hwdb, hwid)
280 logging.info('Verifying system HWID: %r', hwid_properties.hwid)
281 logging.debug('expected system properties:\n%s',
282 YamlWrite(hwid_properties.__dict__))
283 probe_results = probe.Probe()
284 cooked_results = hwid_tool.CookProbeResults(
285 hwdb, probe_results, hwid_properties.board)
286 logging.debug('found system properties:\n%s',
287 YamlWrite(cooked_results.__dict__))
Jon Salz51932222012-06-01 12:54:15 +0800288 _event_log.Log('probe',
289 results=cooked_results.__dict__)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800290 match_errors = []
Tammo Spalink8fab5312012-05-28 18:33:30 +0800291 # TODO(tammo): Refactor to use hwid_tool.MatchHwids() ; this will
292 # make error reporting harder... Or maybe just factor out the
293 # shared matching logic, and add error reporting to that, which the
294 # MatchHwids routine could ignore.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800295 for comp_class, expected_name in hwid_properties.component_map.items():
296 if expected_name == 'ANY':
297 continue
298 if expected_name == cooked_results.matched_components.get(comp_class, None):
299 continue
300 if comp_class in probe_results.missing_components:
301 match_errors.append(' %s component mismatch, expected %s, found nothing'
302 % (comp_class, expected_name))
303 else:
304 probe_value = probe_results.found_components.get(comp_class, None)
305 match_errors.append(' %s component mismatch, expected %s, found %r' %
306 (comp_class, expected_name, probe_value))
307 if match_errors:
308 raise Error('HWID verification FAILED.\n%s' % '\n'.join(match_errors))
309 if hwid_properties.volatile not in cooked_results.matched_volatile_tags:
310 msg = (' HWID specified volatile %s, but found match only for %s' %
311 (hwid_properties.volatile,
312 ', '.join(cooked_results.matched_volatile_tags)))
313 raise Error('HWID verification FAILED.\n%s' % msg)
314 if (hwid_properties.initial_config is not None and
315 hwid_properties.initial_config not in
316 cooked_results.matched_initial_config_tags):
317 msg = (' HWID specified initial_config %s, but only found match for [%s]' %
318 (hwid_properties.initial_config,
319 ', '.join(cooked_results.matched_initial_config_tags)))
320 raise Error('HWID verification FAILED.\n%s' % msg)
321 # TODO(tammo): Verify HWID status is supported (or deprecated for RMA).
322 ro_vpd = ReadRoVpd(main_fw_file)
323 for field in hwid_properties.vpd_ro_field_list:
324 if field not in ro_vpd:
325 raise Error('Missing required VPD field: %s' % field)
326 known_valid_values = vpd_data.KNOWN_VPD_FIELD_DATA.get(field, None)
327 value = ro_vpd[field]
328 if known_valid_values is not None and value not in known_valid_values:
329 raise Error('Invalid VPD entry : field %r, value %r' % (field, value))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800330 rw_vpd = ReadRwVpd(main_fw_file)
331 _event_log.Log(
332 'verify_hwid',
333 matched_components=cooked_results.matched_components,
334 initial_configs=cooked_results.matched_initial_config_tags,
335 volatiles=cooked_results.matched_volatile_tags,
336 ro_vpd=ro_vpd,
337 rw_vpd=rw_vpd)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800338
339
340@Command('verify_keys')
341def VerifyKeys(options):
342 """Verify keys in firmware and SSD match."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800343 script = FindScript('verify_keys.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800344 kernel_device = GetReleaseKernelPartitionPath()
345 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
346 result = Shell('%s %s %s' % (script, kernel_device, main_fw_file))
347 if not result.success:
348 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
349
350
351@Command('set_fw_bitmap_locale')
352def SetFirmwareBitmapLocale(options):
353 """Use VPD locale value to set firmware bitmap default language."""
354 image_file = crosfw.LoadMainFirmware().GetFileName()
355 locale = ReadRoVpd(image_file).get('initial_locale', None)
356 if locale is None:
357 raise Error, 'Missing initial_locale VPD.'
358 bitmap_locales = []
359 with NamedTemporaryFile() as f:
360 Shell('gbb_utility -g --bmpfv=%s %s' % (f.name, image_file))
361 bmpblk_data = bmpblk.unpack_bmpblock(f.read())
362 bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
363 # Some locale values are just a language code and others are a
364 # hyphen-separated language code and country code pair. We care
365 # only about the language code part.
366 language_code = locale.partition('-')[0]
367 if language_code not in bitmap_locales:
368 raise Error, ('Firmware bitmaps do not contain support for the specified '
369 'initial locale language %r' % language_code)
370 else:
371 locale_index = bitmap_locales.index(language_code)
372 logging.info('Firmware bitmap initial locale set to %d (%s).',
373 locale_index, bitmap_locales[locale_index])
374 Shell('crossystem loc_idx=%d' % locale_index)
375
376
377@Command('verify_system_time')
378def VerifySystemTime(options):
379 """Verify system time is later than release filesystem creation time."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800380 script = FindScript('verify_system_time.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800381 rootfs_device = GetReleaseRootPartitionPath()
382 result = Shell('%s %s' % (script, rootfs_device))
383 if not result.success:
384 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
385
386
387@Command('verify_rootfs')
388def VerifyRootFs(options):
389 """Verify rootfs on SSD is valid by checking hash."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800390 script = FindScript('verify_rootfs.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800391 rootfs_device = GetReleaseRootPartitionPath()
392 result = Shell('%s %s' % (script, rootfs_device))
393 if not result.success:
394 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
395
396
397@Command('verify_switch_wp')
398def VerifyWpSwitch(options):
399 """Verify hardware write protection switch is enabled."""
400 if Shell('crossystem wpsw_cur').stdout.strip() != '1':
401 raise Error, 'write protection is disabled'
402
403
404@Command('verify_switch_dev')
405def VerifyDevSwitch(options):
406 """Verify developer switch is disabled."""
Hung-Te Lin8f643e32012-05-23 18:40:47 +0800407 result = Shell('crossystem devsw_cur')
408 if result.success:
409 if result.stdout.strip() != '0':
410 raise Error, 'developer mode is enabled'
411 else:
412 return
413 # Try ChromeOS-EC. This may hang 15 seconds if the EC does not respond.
414 logging.warn('VerifyDevSwitch: Trying ChromeOS-EC...')
415 if not Shell('ectool vboot 0').success:
416 raise Error, 'failed to turn off developer mode.'
417 # TODO(hungte) Verify if the switch is turned off properly, using "ectoo
418 # vboot" and parse the key-value pairs, when the names are determined.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800419
420
421@Command('write_protect')
422def EnableFwWp(options):
423 """Enable then verify firmware write protection."""
424
425 def WriteProtect(fw_file_path, fw_type, section):
426 """Calculate protection size, then invoke flashrom.
427
428 Our supported chips only allow write protecting half their total
429 size, so we parition the flash chipset space accordingly.
430 """
431 raw_image = open(fw_file_path, 'rb').read()
432 image = crosfw.FirmwareImage(raw_image)
433 if not image.has_section(section):
434 raise Error('could not find %s firmware section %s' % (fw_type, section))
435 section_data = image.get_section_area(section)
436 protectable_size = len(raw_image) / 2
437 ro_a = int(section_data[0] / protectable_size)
438 ro_b = int((section_data[0] + section_data[1] - 1) / protectable_size)
439 if ro_a != ro_b:
440 raise Error("%s firmware section %s has illegal size" %
441 (fw_type, section))
442 ro_offset = ro_a * protectable_size
443 logging.debug('write protecting %s', fw_type)
444 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, protectable_size)
445
446 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800447 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800448 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
449 if ec_fw_file is not None:
450 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800451 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800452 else:
453 logging.warning('EC not write protected (seems there is no EC flash).')
454
455
456@Command('clear_gbb_flags')
457def ClearGbbFlags(options):
458 """Zero out the GBB flags, in preparation for transition to release state.
459
460 No GBB flags are set in release/shipping state, but they are useful
461 for factory/development. See "gbb_utility --flags" for details.
462 """
Tammo Spalink461ddce2012-05-10 19:28:55 +0800463 script = FindScript('clear_gbb_flags.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800464 result = Shell(script)
465 if not result.success:
466 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800467 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800468
469
470@Command('prepare_wipe',
471 CmdArg('--fast', action='store_true',
472 help='use non-secure but faster wipe method.'))
473def PrepareWipe(options):
474 """Prepare system for transition to release state in next reboot."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800475 script = FindScript('prepare_wipe.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800476 tag = 'fast' if options.fast else ''
477 rootfs_device = GetReleaseRootPartitionPath()
478 result = Shell('FACTORY_WIPE_TAGS=%s %s %s' % (tag, script, rootfs_device))
479 if not result.success:
480 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
481
482
483@Command('verify',
484 CmdArg('--dev', action='store_true',
485 help='Do not verify switch state (dev mode and fw wp).'),
486 _hwdb_path_cmd_arg)
487def Verify(options):
488 """Verifies if whole factory process is ready for finalization.
489
490 This routine performs all the necessary checks to make sure the
491 device is ready to be finalized, but does not modify state. These
492 checks include dev switch, firmware write protection switch, hwid,
493 system time, keys, and root file system.
494 """
495 if not options.dev:
496 VerifyDevSwitch({})
497 VerifyWpSwitch({})
498 VerifyHwid(options)
499 VerifySystemTime({})
500 VerifyKeys({})
501 VerifyRootFs({})
502
503
Tammo Spalink86a61c62012-05-25 15:10:35 +0800504@Command('log_system_details')
505def LogSystemDetails(options):
506 """Write miscellaneous system details to the event log."""
507 raw_cs_data = Shell('crossystem').stdout.strip().splitlines()
508 # The crossytem output contains many lines like:
509 # 'key = value # description'
510 # Use regexps to pull out the key-value pairs and build a dict.
511 cs_data = dict((k, v.strip()) for k, v in
512 map(lambda x: re.findall(r'\A(\S+)\s+=\s+(.*)#.*\Z', x)[0],
513 raw_cs_data))
514 _event_log.Log(
515 'system_details',
516 platform_name=Shell('mosys platform name').stdout.strip(),
517 crossystem=cs_data,
518 modem_status=Shell('modem status').stdout.splitlines(),
519 ec_wp_status=Shell(
520 'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
521 'flashrom -p internal:bus=lpc --wp-status || '
522 'echo "EC is not available."').stdout,
523 bios_wp_status = Shell(
524 'flashrom -p internal:bus=spi --wp-status').stdout)
525
526
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800527_upload_method_cmd_arg = CmdArg(
528 '--upload_method', metavar='METHOD:PARAM',
529 help=('How to perform the upload. METHOD should be one of '
530 '{ftp, shopfloor, curl, cpfe, custom}.'))
531
532
533@Command('upload_report',
534 _upload_method_cmd_arg)
535def UploadReport(options):
536 """Create and a report containing key device details."""
Tammo Spalink86a61c62012-05-25 15:10:35 +0800537 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
538 device_sn = ro_vpd.get('serial_number', None)
539 if device_sn is None:
540 logging.warning('RO_VPD missing device serial number')
541 device_sn = 'MISSING_SN_' + TimedUuid()
542 target_name = '%s_%s.tbz2' % (TimeString(), device_sn)
543 target_path = os.path.join(gettempdir(), target_name)
544 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
545 tar_cmd = 'cd %s ; tar cjf %s *' % (EVENT_LOG_DIR, target_path)
546 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
547 cmd_result = Shell(tar_cmd)
548 if not cmd_result.success:
549 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
550 (tar_cmd, cmd_result.stderr))
551 if options.upload_method is None or options.upload_method == 'none':
552 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
553 return
554 method, param = options.upload_method.split(':', 1)
555 if method == 'shopfloor':
556 report_upload.ShopFloorUpload(target_path, param)
557 elif method == 'ftp':
558 report_upload.FtpUpload(target_path, 'ftp://' + param)
559 elif method == 'ftps':
560 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
561 elif method == 'cpfe':
562 report_upload.CpfeUpload(target_path, param)
563 else:
564 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800565
566
567@Command('finalize',
568 CmdArg('--dev', action='store_true',
569 help='Do not verify or alter write protection or dev mode.'),
570 CmdArg('--fast', action='store_true',
571 help='use non-secure but faster wipe method.'),
572 _hwdb_path_cmd_arg,
573 _upload_method_cmd_arg)
574def Finalize(options):
575 """Verify system readiness and trigger transition into release state.
576
577 This routine first verifies system state (see verify command), then
578 clears all of the testing flags from the GBB, then modifies firmware
579 bitmaps to match locale. Then it enables firmware write protection
580 and sets the necessary boot flags to cause wipe of the factory image
581 on the next boot.
582 """
583 ClearGbbFlags({})
584 Verify(options)
585 SetFirmwareBitmapLocale({})
586 if not options.dev:
587 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800588 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800589 UploadReport(options)
590 PrepareWipe(options)
591
592
593def Main():
594 """Run sub-command specified by the command line args."""
595 options = ParseCmdline(
596 'Perform Google required factory tests.',
597 CmdArg('-l', '--log', metavar='PATH',
598 help='Write logs to this file.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800599 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800600 SetupLogging(options.verbosity, options.log)
601 logging.debug('gooftool options: %s', repr(options))
602 try:
603 logging.debug('GOOFTOOL command %r', options.command_name)
604 options.command(options)
605 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
606 except Error, e:
607 logging.exception(e)
608 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
609 except Exception, e:
610 logging.exception(e)
611 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
612
613
614if __name__ == '__main__':
615 Main()