• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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