blob: 41b0f15bc961a3bc88a3648196a7f0e037a6c8f1 [file] [log] [blame]
Yong Hong65bda312018-12-13 20:05:58 +08001# Copyright 2018 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import re
6import subprocess
7
Yong Hong65bda312018-12-13 20:05:58 +08008from cros.factory.gooftool import common as gooftool_common
9
10
11# ChromeOS firmware VPD partition names.
12VPD_READONLY_PARTITION_NAME = 'RO_VPD'
13VPD_READWRITE_PARTITION_NAME = 'RW_VPD'
14
15
Fei Shaobd07c9a2020-06-15 19:04:50 +080016class VPDTool:
Yong Hong65bda312018-12-13 20:05:58 +080017 """This class wraps the functions supplied by VPD cmdline tool into methods.
18 """
19 _KEY_PATTERN = re.compile(r'^[a-zA-Z0-9_.]+$')
20
Hung-Te Lin911856a2019-07-05 11:01:27 +080021 def __init__(self, shell=None, raw_file=None):
Yong Hong65bda312018-12-13 20:05:58 +080022 self._shell = shell or gooftool_common.Shell
Hung-Te Lin911856a2019-07-05 11:01:27 +080023 self._raw_file = raw_file
Yong Hong65bda312018-12-13 20:05:58 +080024
25 def GetValue(self, key, default_value=None, partition=None, filename=None):
26 """Gets a VPD value with the specific key.
27
28 If the VPD doesn't contain the data with the given `key`, this function will
29 return `default_value`.
30
31 Args:
32 key: A string of the key of the data to get.
33 default_value: The value to return if the data doesn't exist.
34 filename: Filename of the bios image, see `vpd -h` for detail.
35 partition: Specify VPD partition name in fmap.
36
37 Returns:
38 A string of raw value data or `None`.
39 """
40 self._EnsureIfKeyValid(key)
41 try:
42 return self._InvokeCmd(
43 self._BuildBasicCmd(partition, filename) + ['-g', key])
44 except subprocess.CalledProcessError:
45 if filename is not None:
46 self._CheckFileExistence(filename)
47 return default_value
48
49 def GetAllData(self, partition=None, filename=None):
50 """Gets all VPD data in dictionary format.
51
52 Args:
53 filename: Filename of the bios image, see `vpd -h` for detail.
54 partition: Specify VPD partition name in fmap.
55
56 Returns:
57 A dictionary in which each key-value pair represents a VPD data entry.
58 """
59 raw_data = self._InvokeCmd(
60 self._BuildBasicCmd(partition, filename) + ['-l', '--null-terminated'])
61 result = dict(field.split('=', 1) for field in raw_data.split('\0')
62 if '=' in field)
63 if not result and filename is not None:
64 self._CheckFileExistence(filename)
65 return result
66
67 def UpdateData(self, items, partition=None, filename=None):
68 """Updates VPD data.
69
70 Args:
71 items: Items to set. A value of "None" deletes the item from the VPD.
72 filename: Filename of the bios, see `vpd -h` for detail.
73 partition: Specify VPD partition name in fmap.
74 """
75 cmd = self._BuildBasicCmd(partition, filename)
76 for k, v in items.items():
77 self._EnsureIfKeyValid(k)
78 cmd += ['-d', k] if v is None else ['-s', '%s=%s' % (k, v)]
79 self._InvokeCmd(cmd)
Kevin Lin3cc43ad2020-02-21 17:14:04 +080080 self._UpdateCache()
Yong Hong65bda312018-12-13 20:05:58 +080081
82 def _CheckFileExistence(self, filename):
83 # This could be CheckCall. However, to reduce API dependency, we are
84 # reusing CheckOutput.
85 self._InvokeCmd(['test', '-e', filename])
86
87 def _InvokeCmd(self, cmd):
88 proc_result = self._shell(cmd)
89 if not proc_result.success:
90 raise subprocess.CalledProcessError(proc_result.status, cmd)
91 return proc_result.stdout
92
Hung-Te Lin911856a2019-07-05 11:01:27 +080093 def _BuildBasicCmd(self, partition, filename):
Yong Hong65bda312018-12-13 20:05:58 +080094 cmd = ['vpd']
95 if partition:
96 cmd += ['-i', partition]
97 if filename:
98 cmd += ['-f', filename]
Hung-Te Lin911856a2019-07-05 11:01:27 +080099 elif self._raw_file:
100 cmd += ['--raw', '-f', self._raw_file]
Yong Hong65bda312018-12-13 20:05:58 +0800101 return cmd
102
Kevin Lin3cc43ad2020-02-21 17:14:04 +0800103 def _UpdateCache(self):
104 """Updates VPD cache file."""
105 self._InvokeCmd(['dump_vpd_log', '--force'])
106
Yong Hong65bda312018-12-13 20:05:58 +0800107 @classmethod
108 def _EnsureIfKeyValid(cls, key):
109 if not cls._KEY_PATTERN.match(key):
110 raise ValueError('Invalid VPD key %r (does not match pattern %s)' %
111 (key, cls._KEY_PATTERN.pattern))