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