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 assert 'PARTUUID=%U/PARTNROFF=1' in table 52 table = table.replace('PARTUUID=%U/PARTNROFF=1', rootfs_path) 53 # Cause I/O error on invalid bytes 54 table += ' error_behavior=eio' 55 56 self._remove_mapper() 57 assert not self.os_if.path_exists(_DM_DEV_PATH) 58 self.os_if.run_shell_command( 59 "dmsetup create -r %s --table '%s'" % (_DM_DEVICE, table)) 60 assert self.os_if.path_exists(_DM_DEV_PATH) 61 try: 62 count = self.os_if.get_file_size(_DM_DEV_PATH) 63 return count == partition_size 64 except: 65 return False 66 finally: 67 self._remove_mapper() 68 69 def _remove_mapper(self): 70 """Removes the dm device mapper used by this class.""" 71 if self.os_if.path_exists(_DM_DEV_PATH): 72 self.os_if.run_shell_command_get_output( 73 'dmsetup remove %s' % _DM_DEVICE) 74 75 def init(self, os_if): 76 """Initialize the rootfs handler object. 77 78 @param os_if: OS interface object reference. 79 """ 80 self.os_if = os_if 81 self.root_dev = os_if.get_root_dev() 82 self.kernel_dump_file = os_if.state_dir_file(TMP_FILE_NAME) 83