1# Copyright (c) 2014 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"""A module containing rootfs handler class.""" 5 6import os 7import re 8 9TMP_FILE_NAME = 'kernel_dump' 10 11_KERNEL_MAP = {'A': '2', 'B': '4'} 12_ROOTFS_MAP = {'A': '3', 'B': '5'} 13_DM_DEVICE = 'verifyroot' 14_DM_DEV_PATH = os.path.join('/dev/mapper', _DM_DEVICE) 15 16 17class RootfsHandler(object): 18 """An object to provide ChromeOS root FS related actions. 19 20 It provides functions to verify the integrity of the root FS. 21 """ 22 23 def __init__(self): 24 self.os_if = None 25 self.root_dev = None 26 self.kernel_dump_file = None 27 28 def verify_rootfs(self, section): 29 """Verifies the integrity of the root FS. 30 31 @param section: The rootfs to verify. May be A or B. 32 """ 33 kernel_path = self.os_if.join_part(self.root_dev, 34 _KERNEL_MAP[section.upper()]) 35 rootfs_path = self.os_if.join_part(self.root_dev, 36 _ROOTFS_MAP[section.upper()]) 37 # vbutil_kernel won't operate on a device, only a file. 38 self.os_if.run_shell_command( 39 'dd if=%s of=%s' % (kernel_path, self.kernel_dump_file)) 40 vbutil_kernel = self.os_if.run_shell_command_get_output( 41 'vbutil_kernel --verify %s --verbose' % self.kernel_dump_file) 42 DM_REGEXP = re.compile( 43 r'dm="(?:1 )?vroot none ro(?: 1)?,(0 (\d+) .+)"') 44 match = DM_REGEXP.search('\n'.join(vbutil_kernel)) 45 if not match: 46 return False 47 48 table = match.group(1) 49 partition_size = int(match.group(2)) * 512 50 51 if table.find('PARTUUID=%U/PARTNROFF=1') < 0: 52 return False 53 table = table.replace('PARTUUID=%U/PARTNROFF=1', rootfs_path) 54 # Cause I/O error on invalid bytes 55 table += ' error_behavior=eio' 56 57 self._remove_mapper() 58 assert not self.os_if.path_exists(_DM_DEV_PATH) 59 self.os_if.run_shell_command( 60 "dmsetup create -r %s --table '%s'" % (_DM_DEVICE, table)) 61 assert self.os_if.path_exists(_DM_DEV_PATH) 62 try: 63 count = self.os_if.get_file_size(_DM_DEV_PATH) 64 return count == partition_size 65 except: 66 return False 67 finally: 68 self._remove_mapper() 69 70 def _remove_mapper(self): 71 """Removes the dm device mapper used by this class.""" 72 if self.os_if.path_exists(_DM_DEV_PATH): 73 self.os_if.run_shell_command_get_output( 74 'dmsetup remove %s' % _DM_DEVICE) 75 76 def init(self, os_if): 77 """Initialize the rootfs handler object. 78 79 @param os_if: OS interface object reference. 80 """ 81 self.os_if = os_if 82 self.root_dev = os_if.get_root_dev() 83 self.kernel_dump_file = os_if.state_dir_file(TMP_FILE_NAME) 84