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 5"""A module containing rootfs handler class.""" 6 7import os 8import re 9 10TMP_FILE_NAME = 'kernel_dump' 11 12_KERNEL_MAP = {'A': '2', 'B': '4'} 13_ROOTFS_MAP = {'A': '3', 'B': '5'} 14_DM_DEVICE = 'verifyroot' 15_DM_DEV_PATH = os.path.join('/dev/mapper', _DM_DEVICE) 16 17 18class RootfsHandler(object): 19 """An object to provide ChromeOS root FS related actions. 20 21 It provides functions to verify the integrity of the root FS. 22 """ 23 24 def __init__(self): 25 self.os_if = None 26 self.root_dev = None 27 self.kernel_dump_file = None 28 29 def verify_rootfs(self, section): 30 """Verifies the integrity of the root FS. 31 32 @param section: The rootfs to verify. May be A or B. 33 """ 34 kernel_path = self.os_if.join_part(self.root_dev, 35 _KERNEL_MAP[section.upper()]) 36 rootfs_path = self.os_if.join_part(self.root_dev, 37 _ROOTFS_MAP[section.upper()]) 38 # vbutil_kernel won't operate on a device, only a file. 39 self.os_if.run_shell_command( 40 'dd if=%s of=%s' % (kernel_path, self.kernel_dump_file)) 41 vbutil_kernel = self.os_if.run_shell_command_get_output( 42 'vbutil_kernel --verify %s --verbose' % self.kernel_dump_file) 43 DM_REGEXP = re.compile(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