partition.py revision 861b2d54aec24228cdb3895dbc40062cb40cb2ad
19bfef382c7abd3737e9abe10c958de6b04e290b9mbligh"""
2543dceb5ea025a99639b74e65dfdc867284001c4jadmanskiAPIs to write tests and control files that handle partition creation, deletion
3543dceb5ea025a99639b74e65dfdc867284001c4jadmanskiand formatting.
4543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
5543dceb5ea025a99639b74e65dfdc867284001c4jadmanski@copyright: Google 2006-2008
6543dceb5ea025a99639b74e65dfdc867284001c4jadmanski@author: Martin Bligh (mbligh@google.com)
79bfef382c7abd3737e9abe10c958de6b04e290b9mbligh"""
8d7fb4a6d385df6d97032f8ef9d62c2a3b4c5ab98mbligh
9543dceb5ea025a99639b74e65dfdc867284001c4jadmanskiimport os, re, string, sys, fcntl, logging
10543dceb5ea025a99639b74e65dfdc867284001c4jadmanskifrom autotest_lib.client.bin import os_dep, utils
11543dceb5ea025a99639b74e65dfdc867284001c4jadmanskifrom autotest_lib.client.common_lib import error
12543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
13543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
14543dceb5ea025a99639b74e65dfdc867284001c4jadmanskiclass FsOptions(object):
15543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
16543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    A class encapsulating a filesystem test's parameters.
17543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
18543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # NOTE(gps): This class could grow or be merged with something else in the
19543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # future that actually uses the encapsulated data (say to run mkfs) rather
20543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # than just being a container.
21543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # Ex: fsdev_disks.mkfs_all_disks really should become a method.
22543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
23543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    __slots__ = ('fstype', 'mkfs_flags', 'mount_options', 'fs_tag')
24543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
25543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def __init__(self, fstype, fs_tag, mkfs_flags=None, mount_options=None):
26543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
27543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Fill in our properties.
28543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
29543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param fstype: The filesystem type ('ext2', 'ext4', 'xfs', etc.)
30543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param fs_tag: A short name for this filesystem test to use
31543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                in the results.
32543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param mkfs_flags: Optional. Additional command line options to mkfs.
33543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param mount_options: Optional. The options to pass to mount -o.
34543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
35543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
36543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not fstype or not fs_tag:
37543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise ValueError('A filesystem and fs_tag are required.')
38543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.fstype = fstype
39543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.fs_tag = fs_tag
40543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mkfs_flags = mkfs_flags or ""
41543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mount_options = mount_options or ""
42543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
43543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
44543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def __str__(self):
45543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        val = ('FsOptions(fstype=%r, mkfs_flags=%r, '
46543dceb5ea025a99639b74e65dfdc867284001c4jadmanski               'mount_options=%r, fs_tag=%r)' %
47543dceb5ea025a99639b74e65dfdc867284001c4jadmanski               (self.fstype, self.mkfs_flags,
48543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.mount_options, self.fs_tag))
49543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return val
50543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
51543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
52543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef partname_to_device(part):
53543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """ Converts a partition name to its associated device """
54543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return os.path.join(os.sep, 'dev', part)
55543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
56543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
57543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef list_mount_devices():
58543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    devices = []
59543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # list mounted filesystems
60543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for line in utils.system_output('mount').splitlines():
61543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        devices.append(line.split()[0])
62543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # list mounted swap devices
63543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for line in utils.system_output('swapon -s').splitlines():
64543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if line.startswith('/'):        # skip header line
65543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            devices.append(line.split()[0])
66543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return devices
67543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
68543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
69543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef list_mount_points():
70543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    mountpoints = []
71543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for line in utils.system_output('mount').splitlines():
72543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mountpoints.append(line.split()[2])
73543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return mountpoints
74543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
75543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
76543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef get_iosched_path(device_name, component):
77543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return '/sys/block/%s/queue/%s' % (device_name, component)
78543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
79543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
80543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef wipe_filesystem(job, mountpoint):
81543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    wipe_cmd = 'rm -rf %s/*' % mountpoint
82543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    try:
83543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        utils.system(wipe_cmd)
84543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    except:
85543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        job.record('FAIL', None, wipe_cmd, error.format_error())
86543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        raise
87543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    else:
88543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        job.record('GOOD', None, wipe_cmd)
89543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
90543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
91543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef is_linux_fs_type(device):
92543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
93543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Checks if specified partition is type 83
94543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
95543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param device: the device, e.g. /dev/sda3
96543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
97543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @return: False if the supplied partition name is not type 83 linux, True
98543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            otherwise
99543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
100543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    disk_device = device.rstrip('0123456789')
101543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
102543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # Parse fdisk output to get partition info.  Ugly but it works.
103543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    fdisk_fd = os.popen("/sbin/fdisk -l -u '%s'" % disk_device)
104543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    fdisk_lines = fdisk_fd.readlines()
105543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    fdisk_fd.close()
106543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for line in fdisk_lines:
107543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not line.startswith(device):
108543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
109543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        info_tuple = line.split()
110543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # The Id will be in one of two fields depending on if the boot flag
111543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # was set.  Caveat: this assumes no boot partition will be 83 blocks.
112543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        for fsinfo in info_tuple[4:6]:
113543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if fsinfo == '83':  # hex 83 is the linux fs partition type
114543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return True
115543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return False
116543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
117543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
118543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef get_partition_list(job, min_blocks=0, filter_func=None, exclude_swap=True,
119543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                       open_func=open):
120543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
121543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Get a list of partition objects for all disk partitions on the system.
122543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
123543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Loopback devices and unnumbered (whole disk) devices are always excluded.
124543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
125543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param job: The job instance to pass to the partition object
126543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            constructor.
127543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param min_blocks: The minimum number of blocks for a partition to
128543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            be considered.
129543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param filter_func: A callable that returns True if a partition is
130543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            desired. It will be passed one parameter:
131543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            The partition name (hdc3, etc.).
132543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            Some useful filter functions are already defined in this module.
133543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param exclude_swap: If True any partition actively in use as a swap
134543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            device will be excluded.
135543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param __open: Reserved for unit testing.
136543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
137543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @return: A list of L{partition} objects.
138543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
139543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    active_swap_devices = set()
140543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    if exclude_swap:
141543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        for swapline in open_func('/proc/swaps'):
142543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if swapline.startswith('/'):
143543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                active_swap_devices.add(swapline.split()[0])
144543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
145543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    partitions = []
146543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for partline in open_func('/proc/partitions').readlines():
147543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        fields = partline.strip().split()
148543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if len(fields) != 4 or partline.startswith('major'):
149543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
150543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        (major, minor, blocks, partname) = fields
151543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        blocks = int(blocks)
152543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
153543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # The partition name better end with a digit, else it's not a partition
154543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not partname[-1].isdigit():
155543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
156543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
157543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # We don't want the loopback device in the partition list
158543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if 'loop' in partname:
159543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
160543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
161543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        device = partname_to_device(partname)
162543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if exclude_swap and device in active_swap_devices:
163543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            logging.debug('Skipping %s - Active swap.' % partname)
164543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
165543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
166543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if min_blocks and blocks < min_blocks:
167543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            logging.debug('Skipping %s - Too small.' % partname)
168543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
169543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
170543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if filter_func and not filter_func(partname):
171543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            logging.debug('Skipping %s - Filter func.' % partname)
172543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
173543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
174543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        partitions.append(partition(job, device))
175543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
176543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return partitions
177543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
178543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
179e0493a4af57c1a73376a7bafaed542c01f588196Eric Lidef get_mount_info(partition_list):
180e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    """
181e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    Picks up mount point information about the machine mounts. By default, we
182e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    try to associate mount points with UUIDs, because in newer distros the
183e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    partitions are uniquely identified using them.
184e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    """
185e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    mount_info = set()
186e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    for p in partition_list:
187e0493a4af57c1a73376a7bafaed542c01f588196Eric Li        try:
188861b2d54aec24228cdb3895dbc40062cb40cb2adEric Li            uuid = utils.system_output('blkid -p -s UUID -o value %s' % p.device)
189e0493a4af57c1a73376a7bafaed542c01f588196Eric Li        except error.CmdError:
190e0493a4af57c1a73376a7bafaed542c01f588196Eric Li            # fall back to using the partition
191e0493a4af57c1a73376a7bafaed542c01f588196Eric Li            uuid = p.device
192e0493a4af57c1a73376a7bafaed542c01f588196Eric Li        mount_info.add((uuid, p.get_mountpoint()))
193e0493a4af57c1a73376a7bafaed542c01f588196Eric Li
194e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    return mount_info
195e0493a4af57c1a73376a7bafaed542c01f588196Eric Li
196e0493a4af57c1a73376a7bafaed542c01f588196Eric Li
197543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef filter_partition_list(partitions, devnames):
198543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
199543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Pick and choose which partition to keep.
200543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
201543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    filter_partition_list accepts a list of partition objects and a list
202543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    of strings.  If a partition has the device name of the strings it
203543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    is returned in a list.
204543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
205543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param partitions: A list of L{partition} objects
206543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param devnames: A list of devnames of the form '/dev/hdc3' that
207543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                    specifies which partitions to include in the returned list.
208543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
209543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @return: A list of L{partition} objects specified by devnames, in the
210543dceb5ea025a99639b74e65dfdc867284001c4jadmanski             order devnames specified
211543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
212543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
213543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    filtered_list = []
214543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for p in partitions:
215543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        for d in devnames:
216543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if p.device == d and p not in filtered_list:
217543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                filtered_list.append(p)
218543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
219543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return filtered_list
220543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
221543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
222543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef get_unmounted_partition_list(root_part, job=None, min_blocks=0,
223543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                                 filter_func=None, exclude_swap=True,
224543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                                 open_func=open):
225543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
226543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Return a list of partition objects that are not mounted.
227543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
228543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param root_part: The root device name (without the '/dev/' prefix, example
229543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            'hda2') that will be filtered from the partition list.
230543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
231543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            Reasoning: in Linux /proc/mounts will never directly mention the
232543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            root partition as being mounted on / instead it will say that
233543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            /dev/root is mounted on /. Thus require this argument to filter out
234543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            the root_part from the ones checked to be mounted.
235543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param job, min_blocks, filter_func, exclude_swap, open_func: Forwarded
236543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            to get_partition_list().
237543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @return List of L{partition} objects that are not mounted.
238543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
239543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    partitions = get_partition_list(job=job, min_blocks=min_blocks,
240543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        filter_func=filter_func, exclude_swap=exclude_swap, open_func=open_func)
241543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
242543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    unmounted = []
243543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for part in partitions:
244543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if (part.device != partname_to_device(root_part) and
245543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            not part.get_mountpoint(open_func=open_func)):
246543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            unmounted.append(part)
247543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
248543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return unmounted
249543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
250543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
251543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef parallel(partitions, method_name, *args, **dargs):
252543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
253543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Run a partition method (with appropriate arguments) in parallel,
254543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    across a list of partition objects
255543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
256543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    if not partitions:
257543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return
258543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    job = partitions[0].job
259543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    flist = []
260543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    if (not hasattr(partition, method_name) or
261543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                               not callable(getattr(partition, method_name))):
262543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        err = "partition.parallel got invalid method %s" % method_name
263543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        raise RuntimeError(err)
264543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
265543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for p in partitions:
266543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        print_args = list(args)
267543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        print_args += ['%s=%s' % (key, dargs[key]) for key in dargs.keys()]
268543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('%s.%s(%s)' % (str(p), method_name,
269543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                                     ', '.join(print_args)))
270543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        sys.stdout.flush()
271543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        def _run_named_method(function, part=p):
272543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            getattr(part, method_name)(*args, **dargs)
273543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        flist.append((_run_named_method, ()))
274543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    job.parallel(*flist)
275543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
276543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
277543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef filesystems():
278543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
279543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Return a list of all available filesystems
280543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
281543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return [re.sub('(nodev)?\s*', '', fs) for fs in open('/proc/filesystems')]
282543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
283543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
284543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef unmount_partition(device):
285543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
286543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Unmount a mounted partition
287543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
288543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param device: e.g. /dev/sda1, /dev/hda1
289543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
290543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    p = partition(job=None, device=device)
291543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    p.unmount(record=False)
292543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
293543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
294543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef is_valid_partition(device):
295543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
296543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Checks if a partition is valid
297543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
298543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param device: e.g. /dev/sda1, /dev/hda1
299543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
300543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    parts = get_partition_list(job=None)
301543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    p_list = [ p.device for p in parts ]
302543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    if device in p_list:
303543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return True
304543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
305543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return False
306543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
307543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
308543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef is_valid_disk(device):
309543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
310543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Checks if a disk is valid
311543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
312543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param device: e.g. /dev/sda, /dev/hda
313543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
314543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    partitions = []
315543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for partline in open('/proc/partitions').readlines():
316543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        fields = partline.strip().split()
317543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if len(fields) != 4 or partline.startswith('major'):
318543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            continue
319543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        (major, minor, blocks, partname) = fields
320543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        blocks = int(blocks)
321543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
322543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not partname[-1].isdigit():
323543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # Disk name does not end in number, AFAIK
324543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # so use it as a reference to a disk
325543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if device.strip("/dev/") == partname:
326543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return True
327543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
328543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    return False
329543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
330543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
331543dceb5ea025a99639b74e65dfdc867284001c4jadmanskidef run_test_on_partitions(job, test, partitions, mountpoint_func,
332e0493a4af57c1a73376a7bafaed542c01f588196Eric Li                           tag, fs_opt, do_fsck=True, **dargs):
333543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
334543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Run a test that requires multiple partitions.  Filesystems will be
335543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    made on the partitions and mounted, then the test will run, then the
336e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    filesystems will be unmounted and optionally fsck'd.
337543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
338543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param job: A job instance to run the test
339543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param test: A string containing the name of the test
340543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param partitions: A list of partition objects, these are passed to the
341543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            test as partitions=
342543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param mountpoint_func: A callable that returns a mountpoint given a
343543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            partition instance
344543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param tag: A string tag to make this test unique (Required for control
345543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            files that make multiple calls to this routine with the same value
346543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            of 'test'.)
347543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param fs_opt: An FsOptions instance that describes what filesystem to make
348e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    @param do_fsck: include fsck in post-test partition cleanup.
349543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    @param dargs: Dictionary of arguments to be passed to job.run_test() and
350543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            eventually the test
351543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
352543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # setup the filesystem parameters for all the partitions
353543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    for p in partitions:
354543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        p.set_fs_options(fs_opt)
355543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
356543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # make and mount all the partitions in parallel
357543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    parallel(partitions, 'setup_before_test', mountpoint_func=mountpoint_func)
358543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
359543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    mountpoint = mountpoint_func(partitions[0])
360543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
361543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    # run the test against all the partitions
362543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    job.run_test(test, tag=tag, partitions=partitions, dir=mountpoint, **dargs)
363543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
364e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    parallel(partitions, 'unmount')  # unmount all partitions in parallel
365e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    if do_fsck:
366e0493a4af57c1a73376a7bafaed542c01f588196Eric Li        parallel(partitions, 'fsck')  # fsck all partitions in parallel
367e0493a4af57c1a73376a7bafaed542c01f588196Eric Li    # else fsck is done by caller
368543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
369543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
370543dceb5ea025a99639b74e65dfdc867284001c4jadmanskiclass partition(object):
371543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
372543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Class for handling partitions and filesystems
373543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
374543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
375543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def __init__(self, job, device, loop_size=0, mountpoint=None):
376543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
377543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param job: A L{client.bin.job} instance.
378543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param device: The device in question (e.g."/dev/hda2"). If device is a
379543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                file it will be mounted as loopback. If you have job config
380543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                'partition.partitions', e.g.,
381543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            job.config_set('partition.partitions', ["/dev/sda2", "/dev/sda3"])
382543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                you may specify a partition in the form of "partN" e.g. "part0",
383543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                "part1" to refer to elements of the partition list. This is
384543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                specially useful if you run a test in various machines and you
385543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                don't want to hardcode device names as those may vary.
386543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param loop_size: Size of loopback device (in MB). Defaults to 0.
387543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
388543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # NOTE: This code is used by IBM / ABAT. Do not remove.
389543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        part = re.compile(r'^part(\d+)$')
390543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        m = part.match(device)
391543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if m:
392543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            number = int(m.groups()[0])
393543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            partitions = job.config_get('partition.partitions')
394543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            try:
395543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                device = partitions[number]
396543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            except:
397543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                raise NameError("Partition '" + device + "' not available")
398543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
399543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.device = device
400543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.name = os.path.basename(device)
401543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.job = job
402543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.loop = loop_size
403543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.fstype = None
404543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mountpoint = mountpoint
405543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mkfs_flags = None
406543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mount_options = None
407543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.fs_tag = None
408543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if self.loop:
409543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'dd if=/dev/zero of=%s bs=1M count=%d' % (device, loop_size)
410543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(cmd)
411543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
412543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
413543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def __repr__(self):
414543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return '<Partition: %s>' % self.device
415543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
416543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
417543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def set_fs_options(self, fs_options):
418543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
419543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Set filesystem options
420543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
421543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            @param fs_options: A L{FsOptions} object
422543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
423543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
424543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.fstype = fs_options.fstype
425543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mkfs_flags = fs_options.mkfs_flags
426543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mount_options = fs_options.mount_options
427543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.fs_tag = fs_options.fs_tag
428543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
429543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
430543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def run_test(self, test, **dargs):
431543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.job.run_test(test, dir=self.get_mountpoint(), **dargs)
432543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
433543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
434543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def setup_before_test(self, mountpoint_func):
435543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
436543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Prepare a partition for running a test.  Unmounts any
437543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        filesystem that's currently mounted on the partition, makes a
438543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        new filesystem (according to this partition's filesystem
439543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        options) and mounts it where directed by mountpoint_func.
440543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
441543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param mountpoint_func: A callable that returns a path as a string,
442543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                given a partition instance.
443543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
444543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mountpoint = mountpoint_func(self)
445543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not mountpoint:
446543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise ValueError('Don\'t know where to put this partition')
447543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.unmount(ignore_status=True, record=False)
448543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mkfs()
449543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not os.path.isdir(mountpoint):
450543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            os.makedirs(mountpoint)
451543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.mount(mountpoint)
452543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
453543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
454543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def run_test_on_partition(self, test, mountpoint_func, **dargs):
455543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
456543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Executes a test fs-style (umount,mkfs,mount,test)
457543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
458543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Here we unmarshal the args to set up tags before running the test.
459543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Tests are also run by first umounting, mkfsing and then mounting
460543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        before executing the test.
461543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
462543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param test: name of test to run
463543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param mountpoint_func: function to return mount point string
464543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
465543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        tag = dargs.get('tag')
466543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if tag:
467543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            tag = '%s.%s' % (self.name, tag)
468543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        elif self.fs_tag:
469543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            tag = '%s.%s' % (self.name, self.fs_tag)
470543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        else:
471543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            tag = self.name
472543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
473543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # If there's a 'suffix' argument, append it to the tag and remove it
474543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        suffix = dargs.pop('suffix', None)
475543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if suffix:
476543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            tag = '%s.%s' % (tag, suffix)
477543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
478543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        dargs['tag'] = test + '.' + tag
479543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
480543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        def _make_partition_and_run_test(test_tag, dir=None, **dargs):
481543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            self.setup_before_test(mountpoint_func)
482543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            try:
483543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.run_test(test, tag=test_tag, dir=mountpoint, **dargs)
484543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            finally:
485e0493a4af57c1a73376a7bafaed542c01f588196Eric Li                self.unmount()
486e0493a4af57c1a73376a7bafaed542c01f588196Eric Li                self.fsck()
487e0493a4af57c1a73376a7bafaed542c01f588196Eric Li
488543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
489543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mountpoint = mountpoint_func(self)
490543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
491543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # The tag is the tag for the group (get stripped off by run_group)
492543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # The test_tag is the tag for the test itself
493543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.job.run_group(_make_partition_and_run_test,
494543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                           test_tag=tag, dir=mountpoint, **dargs)
495543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
496543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
497543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def get_mountpoint(self, open_func=open, filename=None):
498543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
499543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Find the mount point of this partition object.
500543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
501543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param open_func: the function to use for opening the file containing
502543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                the mounted partitions information
503543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param filename: where to look for the mounted partitions information
504543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                (default None which means it will search /proc/mounts and/or
505543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                /etc/mtab)
506543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
507543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @returns a string with the mount point of the partition or None if not
508543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                mounted
509543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
510543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if filename:
511543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            for line in open_func(filename).readlines():
512543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                parts = line.split()
513e0493a4af57c1a73376a7bafaed542c01f588196Eric Li                if parts[0] == self.device or parts[1] == self.mountpoint:
514543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                    return parts[1] # The mountpoint where it's mounted
515543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            return None
516543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
517543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # no specific file given, look in /proc/mounts
518543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        res = self.get_mountpoint(open_func=open_func, filename='/proc/mounts')
519543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not res:
520543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # sometimes the root partition is reported as /dev/root in
521543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # /proc/mounts in this case, try /etc/mtab
522543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            res = self.get_mountpoint(open_func=open_func, filename='/etc/mtab')
523543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
524543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # trust /etc/mtab only about /
525543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if res != '/':
526543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                res = None
527543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
528543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return res
529543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
530543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
531543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def mkfs_exec(self, fstype):
532543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
533543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Return the proper mkfs executable based on fs
534543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
535543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if fstype == 'ext4':
536543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if os.path.exists('/sbin/mkfs.ext4'):
537543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return 'mkfs'
538543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # If ext4 supported e2fsprogs is not installed we use the
539543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # autotest supplied one in tools dir which is statically linked"""
540543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            auto_mkfs = os.path.join(self.job.toolsdir, 'mkfs.ext4dev')
541543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if os.path.exists(auto_mkfs):
542543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return auto_mkfs
543543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        else:
544543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            return 'mkfs'
545543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
546543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        raise NameError('Error creating partition for filesystem type %s' %
547543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                        fstype)
548543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
549543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
550543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def mkfs(self, fstype=None, args='', record=True):
551543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
552543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Format a partition to filesystem type
553543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
554543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param fstype: the filesystem type, e.g.. "ext3", "ext2"
555543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param args: arguments to be passed to mkfs command.
556543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param record: if set, output result of mkfs operation to autotest
557543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                output
558543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
559543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
560543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if list_mount_devices().count(self.device):
561543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise NameError('Attempted to format mounted device %s' %
562543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                             self.device)
563543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
564543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not fstype:
565543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if self.fstype:
566543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                fstype = self.fstype
567543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            else:
568543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                fstype = 'ext2'
569543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
570543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if self.mkfs_flags:
571543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            args += ' ' + self.mkfs_flags
572543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if fstype == 'xfs':
573543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            args += ' -f'
574543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
575543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if self.loop:
576543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # BAH. Inconsistent mkfs syntax SUCKS.
577543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if fstype.startswith('ext'):
578543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                args += ' -F'
579543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            elif fstype == 'reiserfs':
580543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                args += ' -f'
581543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
582543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # If there isn't already a '-t <type>' argument, add one.
583543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not "-t" in args:
584543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            args = "-t %s %s" % (fstype, args)
585543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
586543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        args = args.strip()
587543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
588543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mkfs_cmd = "%s %s %s" % (self.mkfs_exec(fstype), args, self.device)
589543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
590543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        sys.stdout.flush()
591543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
592543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # We throw away the output here - we only need it on error, in
593543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # which case it's in the exception
594543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system_output("yes | %s" % mkfs_cmd)
595543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError, e:
596543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            logging.error(e.result_obj)
597543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
598543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('FAIL', None, mkfs_cmd, error.format_error())
599543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise
600543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except:
601543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
602543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('FAIL', None, mkfs_cmd, error.format_error())
603543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise
604543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        else:
605543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
606543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('GOOD', None, mkfs_cmd)
607543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            self.fstype = fstype
608543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
609543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
610543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def get_fsck_exec(self):
611543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
612543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Return the proper mkfs executable based on self.fstype
613543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
614543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if self.fstype == 'ext4':
615543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if os.path.exists('/sbin/fsck.ext4'):
616543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return 'fsck'
617543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # If ext4 supported e2fsprogs is not installed we use the
618543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # autotest supplied one in tools dir which is statically linked"""
619543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            auto_fsck = os.path.join(self.job.toolsdir, 'fsck.ext4dev')
620543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if os.path.exists(auto_fsck):
621543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return auto_fsck
622543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        else:
623543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            return 'fsck'
624543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
625543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        raise NameError('Error creating partition for filesystem type %s' %
626543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                        self.fstype)
627543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
628543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
629543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def fsck(self, args='-fy', record=True):
630543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
631543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Run filesystem check
632543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
633543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param args: arguments to filesystem check tool. Default is "-n"
634543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                which works on most tools.
635543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
636543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
637543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # I hate reiserfstools.
638543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # Requires an explit Yes for some inane reason
639543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        fsck_cmd = '%s %s %s' % (self.get_fsck_exec(), self.device, args)
640543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if self.fstype == 'reiserfs':
641543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            fsck_cmd = 'yes "Yes" | ' + fsck_cmd
642543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        sys.stdout.flush()
643543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
644543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system_output(fsck_cmd)
645543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except:
646543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
647543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('FAIL', None, fsck_cmd, error.format_error())
648543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.TestError('Fsck found errors with the underlying '
649543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                                  'file system')
650543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        else:
651543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
652543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('GOOD', None, fsck_cmd)
653543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
654543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
6556f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li    def mount(self, mountpoint=None, fstype=None, args='', record=True):
656543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
657543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Mount this partition to a mount point
658543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
659543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param mountpoint: If you have not provided a mountpoint to partition
660543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                object or want to use a different one, you may specify it here.
661543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param fstype: Filesystem type. If not provided partition object value
662543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                will be used.
663543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param args: Arguments to be passed to "mount" command.
664543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param record: If True, output result of mount operation to autotest
665543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                output.
666543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
667543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
668543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if fstype is None:
669543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            fstype = self.fstype
670543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        else:
671543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            assert(self.fstype is None or self.fstype == fstype);
672543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
673543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if self.mount_options:
674543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            args += ' -o  ' + self.mount_options
675543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if fstype:
676543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            args += ' -t ' + fstype
677543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if self.loop:
678543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            args += ' -o loop'
679543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        args = args.lstrip()
680543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
681543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not mountpoint and not self.mountpoint:
682543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise ValueError("No mountpoint specified and no default "
683543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                             "provided to this partition object")
684543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not mountpoint:
685543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            mountpoint = self.mountpoint
686543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
687543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mount_cmd = "mount %s %s %s" % (args, self.device, mountpoint)
688543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
689543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if list_mount_devices().count(self.device):
690543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            err = 'Attempted to mount mounted device'
691543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            self.job.record('FAIL', None, mount_cmd, err)
692543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise NameError(err)
693543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if list_mount_points().count(mountpoint):
694543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            err = 'Attempted to mount busy mountpoint'
695543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            self.job.record('FAIL', None, mount_cmd, err)
696543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise NameError(err)
697543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
698543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mtab = open('/etc/mtab')
699543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # We have to get an exclusive lock here - mount/umount are racy
700543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        fcntl.flock(mtab.fileno(), fcntl.LOCK_EX)
701543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        sys.stdout.flush()
702543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
703543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(mount_cmd)
704543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            mtab.close()
705543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except:
706543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            mtab.close()
707543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
708543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('FAIL', None, mount_cmd, error.format_error())
709543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise
710543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        else:
711543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
712543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('GOOD', None, mount_cmd)
713543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            self.fstype = fstype
714543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
715543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
716543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def unmount_force(self):
717543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
718543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Kill all other jobs accessing this partition. Use fuser and ps to find
719543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        all mounts on this mountpoint and unmount them.
720543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
721543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @return: true for success or false for any errors
722543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
723543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
724543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug("Standard umount failed, will try forcing. Users:")
725543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
726543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'fuser ' + self.get_mountpoint()
727543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            logging.debug(cmd)
728543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            fuser = utils.system_output(cmd)
729543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            logging.debug(fuser)
730543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            users = re.sub('.*:', '', fuser).split()
731543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            for user in users:
732543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                m = re.match('(\d+)(.*)', user)
733543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                (pid, usage) = (m.group(1), m.group(2))
734543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                try:
735543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                    ps = utils.system_output('ps -p %s | sed 1d' % pid)
736543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                    logging.debug('%s %s %s' % (usage, pid, ps))
737543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                except Exception:
738543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                    pass
739543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                utils.system('ls -l ' + self.device)
740543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                umount_cmd = "umount -f " + self.device
741543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                utils.system(umount_cmd)
742543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return True
743543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError:
744543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            logging.debug('Umount_force failed for %s' % self.device)
745543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            return False
746543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
747543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
748543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
749543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def unmount(self, ignore_status=False, record=True):
750543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
751543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Umount this partition.
752543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
753543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        It's easier said than done to umount a partition.
754543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        We need to lock the mtab file to make sure we don't have any
755543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        locking problems if we are umounting in paralllel.
756543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
757543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        If there turns out to be a problem with the simple umount we
758543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        end up calling umount_force to get more  agressive.
759543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
760543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param ignore_status: should we notice the umount status
761543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param record: if True, output result of umount operation to
762543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                autotest output
763543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
764543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
765543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mountpoint = self.get_mountpoint()
766543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if not mountpoint:
767543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # It's not even mounted to start with
768543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record and not ignore_status:
769543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                msg = 'umount for dev %s has no mountpoint' % self.device
770543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('FAIL', None, msg, 'Not mounted')
771543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            return
772543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
773543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        umount_cmd = "umount " + mountpoint
774543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        mtab = open('/etc/mtab')
775543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
776543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        # We have to get an exclusive lock here - mount/umount are racy
777543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        fcntl.flock(mtab.fileno(), fcntl.LOCK_EX)
778543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        sys.stdout.flush()
779543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
780543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(umount_cmd)
781543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            mtab.close()
782543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record:
783543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('GOOD', None, umount_cmd)
784543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except (error.CmdError, IOError):
785543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            mtab.close()
786543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
787543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # Try the forceful umount
788543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if self.unmount_force():
789543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                return
790543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
791543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            # If we are here we cannot umount this partition
792543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            if record and not ignore_status:
793543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                self.job.record('FAIL', None, umount_cmd, error.format_error())
794543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise
795543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
796543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
797543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def wipe(self):
798543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
799543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Delete all files of a given partition filesystem.
800543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
801543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        wipe_filesystem(self.job, self.get_mountpoint())
802543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
803543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
804543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def get_io_scheduler_list(self, device_name):
805543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        names = open(self.__sched_path(device_name)).read()
806543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return names.translate(string.maketrans('[]', '  ')).split()
807543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
808543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
809543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def get_io_scheduler(self, device_name):
810543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return re.split('[\[\]]',
811543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                        open(self.__sched_path(device_name)).read())[1]
812543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
813543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
814543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def set_io_scheduler(self, device_name, name):
815543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        if name not in self.get_io_scheduler_list(device_name):
816543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise NameError('No such IO scheduler: %s' % name)
817543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        f = open(self.__sched_path(device_name), 'w')
818543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        f.write(name)
819543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        f.close()
820543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
821543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
822543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def __sched_path(self, device_name):
823543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return '/sys/block/%s/queue/scheduler' % device_name
824543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
825543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
826543dceb5ea025a99639b74e65dfdc867284001c4jadmanskiclass virtual_partition:
827543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
828543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    Handles block device emulation using file images of disks.
829543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    It's important to note that this API can be used only if
830543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    we have the following programs present on the client machine:
831543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
832543dceb5ea025a99639b74e65dfdc867284001c4jadmanski     * sfdisk
833543dceb5ea025a99639b74e65dfdc867284001c4jadmanski     * losetup
834543dceb5ea025a99639b74e65dfdc867284001c4jadmanski     * kpartx
835543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    """
836543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def __init__(self, file_img, file_size):
837543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
838543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Creates a virtual partition, keeping record of the device created
839543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        under /dev/mapper (device attribute) so test writers can use it
840543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        on their filesystem tests.
841543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
842543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param file_img: Path to the desired disk image file.
843543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param file_size: Size of the desired image in Bytes.
844543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
845543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Sanity check before attempting to create virtual '
846543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                      'partition')
847543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
848543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            os_dep.commands('sfdisk', 'losetup', 'kpartx')
849543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except ValueError, e:
850543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = 'Unable to create virtual partition: %s' % e
851543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
852543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
853543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Creating virtual partition')
854543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.img = self._create_disk_img(file_img, file_size)
855543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.loop = self._attach_img_loop(self.img)
856543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self._create_single_partition(self.loop)
857543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self.device = self._create_entries_partition(self.loop)
858543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Virtual partition successfuly created')
859543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Image disk: %s', self.img)
860543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Loopback device: %s', self.loop)
861543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Device path: %s', self.device)
862543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
863543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
864543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def destroy(self):
865543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
866543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Removes the virtual partition from /dev/mapper, detaches the image file
867543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        from the loopback device and removes the image file.
868543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
869543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Removing virtual partition - device %s', self.device)
870543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self._remove_entries_partition()
871543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self._detach_img_loop()
872543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        self._remove_disk_img()
873543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
874543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
875543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def _create_disk_img(self, img_path, size):
876543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
877543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Creates a disk image using dd.
878543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
879543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param img_path: Path to the desired image file.
880543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param size: Size of the desired image in Bytes.
881543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @returns: Path of the image created.
882543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
883543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Creating disk image %s, size = %d Bytes', img_path, size)
884543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
885543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'dd if=/dev/zero of=%s bs=1024 count=%d' % (img_path, size)
886543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(cmd)
887543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError, e:
888543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = 'Error creating disk image %s: %s' % (img_path, e)
889543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
890543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return img_path
891543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
892543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
893543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def _attach_img_loop(self, img_path):
894543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
895543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Attaches a file image to a loopback device using losetup.
896543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
897543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param img_path: Path of the image file that will be attached to a
898543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                loopback device
899543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @returns: Path of the loopback device associated.
900543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
901543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Attaching image %s to a loop device', img_path)
902543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
903543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'losetup -f'
904543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            loop_path = utils.system_output(cmd)
905543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'losetup -f %s' % img_path
906543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(cmd)
907543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError, e:
908543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = 'Error attaching image %s to a loop device: %s' % \
909543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                     (img_path, e)
910543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
911543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return loop_path
912543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
913543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
914543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def _create_single_partition(self, loop_path):
915543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
916543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Creates a single partition encompassing the whole 'disk' using cfdisk.
917543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
918543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param loop_path: Path to the loopback device.
919543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
920543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Creating single partition on %s', loop_path)
921543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
922543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            single_part_cmd = '0,,c\n'
923543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            sfdisk_file_path = '/tmp/create_partition.sfdisk'
924543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            sfdisk_cmd_file = open(sfdisk_file_path, 'w')
925543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            sfdisk_cmd_file.write(single_part_cmd)
926543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            sfdisk_cmd_file.close()
927543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system('sfdisk %s < %s' % (loop_path, sfdisk_file_path))
928543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError, e:
929543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = 'Error partitioning device %s: %s' % (loop_path, e)
930543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
931543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
932543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
933543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def _create_entries_partition(self, loop_path):
934543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
935543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Takes the newly created partition table on the loopback device and
936543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        makes all its devices available under /dev/mapper. As we previously
937543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        have partitioned it using a single partition, only one partition
938543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        will be returned.
939543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
940543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        @param loop_path: Path to the loopback device.
941543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
942543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Creating entries under /dev/mapper for %s loop dev',
943543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                      loop_path)
944543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
945543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'kpartx -a %s' % loop_path
946543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(cmd)
947543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            l_cmd = 'kpartx -l %s | cut -f1 -d " "' % loop_path
948543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            device = utils.system_output(l_cmd)
949543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError, e:
950543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = 'Error creating entries for %s: %s' % (loop_path, e)
951543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
952543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        return os.path.join('/dev/mapper', device)
953543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
954543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
955543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def _remove_entries_partition(self):
956543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
957543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Removes the entries under /dev/mapper for the partition associated
958543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        to the loopback device.
959543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
960543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Removing the entry on /dev/mapper for %s loop dev',
961543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                      self.loop)
962543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
963543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'kpartx -d %s' % self.loop
964543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(cmd)
965543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError, e:
966543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = 'Error removing entries for loop %s: %s' % (self.loop, e)
967543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
968543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
969543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
970543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def _detach_img_loop(self):
971543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
972543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Detaches the image file from the loopback device.
973543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
974543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Detaching image %s from loop device %s', self.img,
975543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                      self.loop)
976543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
977543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            cmd = 'losetup -d %s' % self.loop
978543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            utils.system(cmd)
979543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except error.CmdError, e:
980543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = ('Error detaching image %s from loop device %s: %s' %
981543dceb5ea025a99639b74e65dfdc867284001c4jadmanski                    (self.img, self.loop, e))
982543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
983543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
984543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
985543dceb5ea025a99639b74e65dfdc867284001c4jadmanski    def _remove_disk_img(self):
986543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
987543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        Removes the disk image.
988543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        """
989543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        logging.debug('Removing disk image %s', self.img)
990543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        try:
991543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            os.remove(self.img)
992543dceb5ea025a99639b74e65dfdc867284001c4jadmanski        except:
993543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            e_msg = 'Error removing image file %s' % self.img
994543dceb5ea025a99639b74e65dfdc867284001c4jadmanski            raise error.AutotestError(e_msg)
995543dceb5ea025a99639b74e65dfdc867284001c4jadmanski
996543dceb5ea025a99639b74e65dfdc867284001c4jadmanski# import a site partition module to allow it to override functions
99769bdaacdf2b8161ae95dded60ed6eedbeb5f8f47jadmanskitry:
99869bdaacdf2b8161ae95dded60ed6eedbeb5f8f47jadmanski    from autotest_lib.client.bin.site_partition import *
99969bdaacdf2b8161ae95dded60ed6eedbeb5f8f47jadmanskiexcept ImportError:
100069bdaacdf2b8161ae95dded60ed6eedbeb5f8f47jadmanski    pass
1001