OLD | NEW |
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import logging | 5 import logging |
6 import mmap | 6 import mmap |
7 import os | 7 import os |
8 import time | 8 import time |
9 from autotest_lib.client.bin import os_dep, test | 9 from autotest_lib.client.bin import os_dep, test |
10 from autotest_lib.client.common_lib import error, utils | 10 from autotest_lib.client.common_lib import error, utils |
11 | 11 |
12 """ a wrapper for using verity/dm-verity with a test backing store """ | 12 """ a wrapper for using verity/dm-verity with a test backing store """ |
13 | 13 |
14 # enum for the 3 possible values of the module parameter. | 14 # enum for the 3 possible values of the module parameter. |
15 ERROR_BEHAVIOR_ERROR = 'eio' | 15 ERROR_BEHAVIOR_ERROR = 'eio' |
16 ERROR_BEHAVIOR_REBOOT = 'panic' | 16 ERROR_BEHAVIOR_REBOOT = 'panic' |
17 ERROR_BEHAVIOR_IGNORE = 'none' | 17 ERROR_BEHAVIOR_IGNORE = 'none' |
18 ERROR_BEHAVIOR_NOTIFIER = 'notify' # for platform specific behavior. | 18 ERROR_BEHAVIOR_NOTIFIER = 'notify' # for platform specific behavior. |
19 | 19 |
20 # Default configuration for verity_image | 20 # Default configuration for verity_image |
21 DEFAULT_TARGET_NAME = 'verity_image' | 21 DEFAULT_TARGET_NAME = 'verity_image' |
22 DEFAULT_DEPTH = 1 | |
23 DEFAULT_ALG = 'sha1' | 22 DEFAULT_ALG = 'sha1' |
24 DEFAULT_IMAGE_SIZE_IN_BLOCKS = 100 | 23 DEFAULT_IMAGE_SIZE_IN_BLOCKS = 100 |
25 DEFAULT_ERROR_BEHAVIOR = ERROR_BEHAVIOR_ERROR | 24 DEFAULT_ERROR_BEHAVIOR = ERROR_BEHAVIOR_ERROR |
26 # TODO(wad) make this configurable when dm-verity doesn't hard-code 4096. | 25 # TODO(wad) make this configurable when dm-verity doesn't hard-code 4096. |
27 BLOCK_SIZE = 4096 | 26 BLOCK_SIZE = 4096 |
28 | 27 |
29 class verity_image(object): | 28 class verity_image(object): |
30 """ a helper for creating dm-verity targets for testing. | 29 """ a helper for creating dm-verity targets for testing. |
31 | 30 |
32 To use, | 31 To use, |
33 vi = verity_image() | 32 vi = verity_image() |
34 vi.initialize(self.tmpdir, "dmveritytesta") | 33 vi.initialize(self.tmpdir, "dmveritytesta") |
35 # Create a 409600 byte image with /bin/ls on it | 34 # Create a 409600 byte image with /bin/ls on it |
36 # The size in bytes is returned. | 35 # The size in bytes is returned. |
37 backing_path = vi.create_backing_image(100, copy_files=['/bin/ls']) | 36 backing_path = vi.create_backing_image(100, copy_files=['/bin/ls']) |
38 # Performs hashing of the backing_path and sets up a device. | 37 # Performs hashing of the backing_path and sets up a device. |
39 loop_dev = vi.prepare_backing_device() | 38 loop_dev = vi.prepare_backing_device() |
40 # Sets up the mapped device and returns the path: | 39 # Sets up the mapped device and returns the path: |
41 # E.g., /dev/mapper/autotest_dmveritytesta | 40 # E.g., /dev/mapper/autotest_dmveritytesta |
42 dev = vi.create_verity_device() | 41 dev = vi.create_verity_device() |
43 # Access the mapped device using the returned string. | 42 # Access the mapped device using the returned string. |
44 | 43 |
45 TODO(wad) add direct verified and backing store access functions | 44 TODO(wad) add direct verified and backing store access functions |
46 to make writing modifiers easier (e.g., mmap). | 45 to make writing modifiers easier (e.g., mmap). |
47 """ | 46 """ |
48 # Define the command template constants. | 47 # Define the command template constants. |
49 verity_cmd = 'verity create %d %s %s %d %s' | 48 verity_cmd = 'verity create 0 %s %s %d %s' |
50 dd_cmd = 'dd if=/dev/zero of=%s bs=4096 count=0 seek=%d' | 49 dd_cmd = 'dd if=/dev/zero of=%s bs=4096 count=0 seek=%d' |
51 mkfs_cmd = 'mkfs.ext3 -b 4096 -F %s' | 50 mkfs_cmd = 'mkfs.ext3 -b 4096 -F %s' |
52 dmsetup_cmd = "dmsetup -r create autotest_%s --table '%s'" | 51 dmsetup_cmd = "dmsetup -r create autotest_%s --table '%s'" |
53 | 52 |
54 def reset(self): | 53 def reset(self): |
55 """Idempotent call which will free any claimed system resources""" | 54 """Idempotent call which will free any claimed system resources""" |
56 # Pre-initialize these values to None | 55 # Pre-initialize these values to None |
57 for attr in ['mountpoint', 'device', 'loop', 'file', 'hash_file']: | 56 for attr in ['mountpoint', 'device', 'loop', 'file', 'hash_file']: |
58 if not hasattr(self, attr): | 57 if not hasattr(self, attr): |
59 setattr(self, attr, None) | 58 setattr(self, attr, None) |
(...skipping 14 matching lines...) Expand all Loading... |
74 | 73 |
75 if self.file is not None: | 74 if self.file is not None: |
76 os.remove(self.file) | 75 os.remove(self.file) |
77 self.file = None | 76 self.file = None |
78 | 77 |
79 if self.hash_file is not None: | 78 if self.hash_file is not None: |
80 os.remove(self.hash_file) | 79 os.remove(self.hash_file) |
81 self.hash_file = None | 80 self.hash_file = None |
82 | 81 |
83 self.alg = DEFAULT_ALG | 82 self.alg = DEFAULT_ALG |
84 self.depth = DEFAULT_DEPTH | |
85 self.error_behavior = DEFAULT_ERROR_BEHAVIOR | 83 self.error_behavior = DEFAULT_ERROR_BEHAVIOR |
86 self.blocks = DEFAULT_IMAGE_SIZE_IN_BLOCKS | 84 self.blocks = DEFAULT_IMAGE_SIZE_IN_BLOCKS |
87 self.file = None | 85 self.file = None |
88 self.has_fs = False | 86 self.has_fs = False |
89 self.hash_file = None | 87 self.hash_file = None |
90 self.table = None | 88 self.table = None |
91 self.target_name = DEFAULT_TARGET_NAME | 89 self.target_name = DEFAULT_TARGET_NAME |
92 | 90 |
93 self.__initialized = False | 91 self.__initialized = False |
94 | 92 |
(...skipping 14 matching lines...) Expand all Loading... |
109 def _create_fs(self, copy_files): | 107 def _create_fs(self, copy_files): |
110 """sets up ext3 on the image""" | 108 """sets up ext3 on the image""" |
111 self.has_fs = True | 109 self.has_fs = True |
112 utils.system(self.mkfs_cmd % self.file) | 110 utils.system(self.mkfs_cmd % self.file) |
113 if type(copy_files) is list: | 111 if type(copy_files) is list: |
114 for file in copy_files: | 112 for file in copy_files: |
115 pass # TODO(wad) | 113 pass # TODO(wad) |
116 | 114 |
117 def _hash_image(self): | 115 def _hash_image(self): |
118 """runs verity over the image and saves the device mapper table""" | 116 """runs verity over the image and saves the device mapper table""" |
119 self.table = utils.system_output(self.verity_cmd % (self.depth, | 117 self.table = utils.system_output(self.verity_cmd % (self.alg, |
120 self.alg, | |
121 self.file, | 118 self.file, |
122 self.blocks, | 119 self.blocks, |
123 self.hash_file)) | 120 self.hash_file)) |
124 # The verity tool doesn't include a templated error value. | 121 # The verity tool doesn't include a templated error value. |
125 # For now, we add one. | 122 # For now, we add one. |
126 self.table += " ERROR_BEHAVIOR" | 123 self.table += " ERROR_BEHAVIOR" |
127 logging.info("table is %s" % self.table) | 124 logging.info("table is %s" % self.table) |
128 | 125 |
129 def _append_hash(self): | 126 def _append_hash(self): |
130 # TODO(wad) use native python file I/O | 127 # TODO(wad) use native python file I/O |
131 utils.system('cat %s >> %s' % (self.hash_file, self.file)) | 128 utils.system('cat %s >> %s' % (self.hash_file, self.file)) |
132 | 129 |
133 def _setup_loop(self): | 130 def _setup_loop(self): |
134 # Setup a loop device | 131 # Setup a loop device |
135 self.loop = utils.system_output('losetup -f') | 132 self.loop = utils.system_output('losetup -f') |
136 utils.system('losetup %s %s' % (self.loop, self.file)) | 133 utils.system('losetup %s %s' % (self.loop, self.file)) |
137 | 134 |
138 def _setup_target(self): | 135 def _setup_target(self): |
139 # Update the table with the loop dev | 136 # Update the table with the loop dev |
140 self.table = self.table.replace('HASH_DEV', self.loop) | 137 self.table = self.table.replace('HASH_DEV', self.loop) |
141 self.table = self.table.replace('ROOT_DEV', self.loop) | 138 self.table = self.table.replace('ROOT_DEV', self.loop) |
142 self.table = self.table.replace('ERROR_BEHAVIOR', self.error_behavior) | 139 self.table = self.table.replace('ERROR_BEHAVIOR', self.error_behavior) |
143 | 140 |
144 utils.system(self.dmsetup_cmd % (self.target_name, self.table)) | 141 utils.system(self.dmsetup_cmd % (self.target_name, self.table)) |
145 self.device = "/dev/mapper/autotest_%s" % self.target_name | 142 self.device = "/dev/mapper/autotest_%s" % self.target_name |
146 | 143 |
147 def initialize(self, | 144 def initialize(self, |
148 tmpdir, | 145 tmpdir, |
149 target_name, | 146 target_name, |
150 depth=DEFAULT_DEPTH, | |
151 alg=DEFAULT_ALG, | 147 alg=DEFAULT_ALG, |
152 size_in_blocks=DEFAULT_IMAGE_SIZE_IN_BLOCKS, | 148 size_in_blocks=DEFAULT_IMAGE_SIZE_IN_BLOCKS, |
153 error_behavior=DEFAULT_ERROR_BEHAVIOR): | 149 error_behavior=DEFAULT_ERROR_BEHAVIOR): |
154 """Performs any required system-level initialization before use. | 150 """Performs any required system-level initialization before use. |
155 """ | 151 """ |
156 try: | 152 try: |
157 os_dep.commands('losetup', 'mkfs.ext3', 'dmsetup', 'verity', 'dd', | 153 os_dep.commands('losetup', 'mkfs.ext3', 'dmsetup', 'verity', 'dd', |
158 'dumpe2fs') | 154 'dumpe2fs') |
159 except ValueError, e: | 155 except ValueError, e: |
160 logging.error('verity_image cannot be used without: %s' % e) | 156 logging.error('verity_image cannot be used without: %s' % e) |
161 return False | 157 return False |
162 | 158 |
163 # Used for the mapper device name and the tmpfile names. | 159 # Used for the mapper device name and the tmpfile names. |
164 self.target_name = target_name | 160 self.target_name = target_name |
165 | 161 |
166 # Reserve some files to use. | 162 # Reserve some files to use. |
167 self.file = os.tempnam(tmpdir, '%s.img.' % self.target_name) | 163 self.file = os.tempnam(tmpdir, '%s.img.' % self.target_name) |
168 self.hash_file = os.tempnam(tmpdir, '%s.hash.' % self.target_name) | 164 self.hash_file = os.tempnam(tmpdir, '%s.hash.' % self.target_name) |
169 | 165 |
170 # Set up the configurable bits. | 166 # Set up the configurable bits. |
171 self.alg = alg | 167 self.alg = alg |
172 self.depth = depth | |
173 self.error_behavior = error_behavior | 168 self.error_behavior = error_behavior |
174 self.blocks = size_in_blocks | 169 self.blocks = size_in_blocks |
175 | 170 |
176 self.__initialized = True | 171 self.__initialized = True |
177 return True | 172 return True |
178 | 173 |
179 def create_backing_image(self, size_in_blocks, with_fs=True, | 174 def create_backing_image(self, size_in_blocks, with_fs=True, |
180 copy_files=None): | 175 copy_files=None): |
181 """Creates an image file of the given number of blocks and if specified | 176 """Creates an image file of the given number of blocks and if specified |
182 will create a filesystem and copy any files in a copy_files list to | 177 will create a filesystem and copy any files in a copy_files list to |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 | 253 |
259 mapped_dev = self.verity.create_verity_device() | 254 mapped_dev = self.verity.create_verity_device() |
260 | 255 |
261 # Now check for failure. | 256 # Now check for failure. |
262 if self.verity.verifiable() is not expected: | 257 if self.verity.verifiable() is not expected: |
263 raise error.TestFail( | 258 raise error.TestFail( |
264 '%s: verity.verifiable() not as expected (%s)' % | 259 '%s: verity.verifiable() not as expected (%s)' % |
265 (modifier.__name__, expected)) | 260 (modifier.__name__, expected)) |
266 tries += 1 | 261 tries += 1 |
267 | 262 |
OLD | NEW |