HEX
Server: Apache
System: Linux wp02.tdr-lab.com 3.10.0-1160.42.2.el7.x86_64 #1 SMP Tue Sep 7 14:49:57 UTC 2021 x86_64
User: kusanagi (1001)
PHP: 7.4.23
Disabled: NONE
Upload Files
File: //lib64/python2.7/site-packages/block/device.py
#!/usr/bin/python
# 
# Copyright 2005-2007 Red Hat, Inc.
# 
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) version 3.
# 
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
# 
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# 


import sys as _sys
import os as _os
import stat as _stat
import string as _string

def DeviceMaps():
    import dm as _dm
    mlist = _dm.maps()
    del _dm
    devs = {}
    for m in mlist:
        devs[m.dev] = m
        
    maps = {}
    for d,m in devs.items():
        mdeps = filter(lambda x: devs.has_key(x), m.deps)
        for mdep in mdeps:
            key = devs[mdep]
            maps.setdefault(key, []).append(m)
    return maps

def removeDeviceMap(map):
    maps = DeviceMaps()
    try:
        for m in maps[map]:
            removeDeviceMap(m)
    except KeyError:
        pass
    map.remove()

def map_dev(path):
    if path[0] != '/':
        return path

    try:
        statinfo = _os.stat(path)
        if not _stat.S_ISBLK(statinfo.st_mode):
            return path

        return "%d:%d" % (statinfo.st_rdev/256, statinfo.st_rdev%256, )
    except:
        return path

# Helper function for get_map
# The tables will be considered the same if for every row, with everything else
# being the same, they contain the same sets of devices.
def compare_tables(t1, t2):
    for table1, table2 in zip(t1, t2):
        table1 = str(table1).strip().split(' ')
        table2 = str(table2).strip().split(' ')
        table1sets = []
        table2sets = []

        # We do this to avoid the index out of range exception
        if len(table1) != len(table2):
            return False

        for i in range(len(table1)):
            d1 = map_dev(table1[i])
            d2 = map_dev(table2[i])

            # when at least one changes its a device.
            if (table1[i] != d1) or (table2[i] != d2):
                # The d{1,2} will always have the major:minor string
                # We also need what comes after the dev, the offset.
                try:
                    table1sets.append("%s %s" % (d1, table1[i+1]))
                    table2sets.append("%s %s" % (d2, table2[i+1]))
                    i += 1
                except IndexError, msg:
                    # The device must have an offset, if not its nonesense
                    return False
                continue

            # these are not devices
            if d1 == d2:
                continue

            if d1 != d2:
                return False

        # For mirror sets the devices can be in disorder.
        if table1[2] == "mirror":
            if set(table1sets) != set(table2sets):
                return False

        # For none mirror the devs have to be in order.
        else:
            for i in range(len(table1sets)):
                if table1sets[i] != table2sets[i]:
                    return False

    return True

class BlockDev:
    def get_major(self):
        return self._BlockDev__device.major
    def set_major(self, major):
        self._BlockDev__device.major = major
    major = property(get_major, set_major, None, "major device number")

    def get_minor(self):
        return self.__device.minor
    def set_minor(self, minor):
        self._BlockDev__device.minor = minor
    minor = property(get_minor, set_minor, None, "minor device number")

    def get_device(self):
        return self._BlockDev__device
    device = property(get_device, None, None, "device number")

    def get_dmdev(self):
        return "%s:%s" % (self._BlockDev__device.major, self._BlockDev__device.minor)
    dmdev = property(get_dmdev, None, None, "device number formatted for dm")

    def get_path(self):
        return self._BlockDev__path
    def set_path(self, path):
        self._BlockDev__path = str(path)
    path = property(get_path, set_path, None, "path to device node")

    def get_mode(self):
        return self._BlockDev__device.mode
    def set_mode(self, mode):
        self._BlockDev__device.mode = int(mode)
    mode = property(get_mode, set_mode, None, "mode for device node")

    def __init__(self, path=None, major=None, minor=None, dev=None):
        self._BlockDev__context = None

        self._BlockDev__path = None
        if not path is None:
            self.FromFile(path)
        elif not (major is None and minor is None):
            self.FromMajorMinor(major, minor)
        elif not dev is None:
            self.FromDev(dev)
        else:
            import dm as _dm
            self._BlockDev__device = _dm.device(0,0)
            del _dm

        # self.sysfs = None # XXX not handling yet
        # XXX should probe parents/children/etc
        self.parents = []
        self.children = []

        self.group = None
        self.group_position = None
        self.group_siblings = []

    def FromFile(self, path):
        import dm as _dm

        path = str(path)
        self._BlockDev__path = path
        self._BlockDev__device = _dm.device(path=path)
        del _dm
        return self;

    def FromMajorMinor(self, major, minor):
        import dm as _dm

        self._BlockDev__device = _dm.device(major, minor)
        del _dm
        return self

    def FromDev(self, dev):
        import dm as _dm

        self._BlockDev__device == _dm.device(0,0)
        self._BlockDev__device.dev = dev
        del _dm
        return self

    def create(self, path=None, mode=None, context=None):
        args = {}
        if path is None:
            path = self.path
        if path is None:
            raise ValueError, "no path set for %s" % (self,)
        args['path'] = path
        args['mode'] = self.mode
        if not mode is None:
            args['mode'] = mode
        if context is None:
            context = self._BlockDev__context
        if not context is None:
            args['context'] = context

        return apply(self.device.mknod, (), args)

    def output(self, *args):
        for x in args:
            print x

    def remove(self):
        if not self.path:
            raise RuntimeError, "no path set for %s" % (self,)
        if self.path.split('/')[-1].startswith('VolGroup'):
            raise RuntimeError, "trying to unlink %s" % (self.path,)
        _os.unlink(self.path)

class Device:
    def get_major(self):
        return self.__bdev.major
    def set_major(self, major):
        self.__bdev.major = major
    major = property(get_major, set_major, None, "major device number")

    def get_minor(self):
        return self.__bdev.minor
    def set_minor(self, major):
        self.__bdev.minor = major
    minor = property(get_major, set_major, None, "major device number")

    def get_dmdev(self):
        return self.__bdev.dmdev
    dmdev = property(get_dmdev, None, None, "device number formatted for dm")

    def get_map(self):
        return self.__map
    def set_map(self, map):
        # XXX type chek this
        self.__map = map
    map = property(get_map, set_map, None, "device map for this device")

    def __init__(self, bdev=BlockDev(), map=None):
        if not isinstance(bdev, BlockDev):
            raise TypeError, "bdev must be an instance of block.BlockDev"
        self.__bdev = bdev
        self.__map = map

    def FromFile(self, path):
        self.__bdev = BlockDev().FromFile(path)
        self.__map = None

from UserDict import IterableUserDict as _IUD
class MPNameCache(_IUD):
    import dm as _dm
    # we'll get other maps here which will never be dereffed, but we
    # also won't wind up using them for .new(), so that's good.
    data = {}
    for map in _dm.maps():
        data.setdefault(map.name, 1)
    del _dm

    def __init__(self):
        _IUD.__init__(self)
        self.data = MPNameCache.data

    def new(self):
        n = 0
        while True:
            name = 'mpath%s' % (n,)
            if self.try_get(name):
                return name
            n += 1

    def get(self, name):
        self.setdefault(name, 0)
        self[name] += 1
        return name

    def try_get(self, name):
        if not self.has_key(name):
            self.get(name)
            return True
        return False

    def put(self, name):
        self[name] -= 1
        if self[name] == 0:
            del self[name]

    def rename(self, old_name, new_name):
        self[new_name] = self[old_name]
        del self[old_name]
        return new_name

nameCache = MPNameCache()
del _IUD

class MultiPath:
    def __init__(self, *bdevs):
        self._MultiPath__prefix = "/dev/mapper/"
        self._MultiPath__bdev = None
        self._MultiPath__table = None
        self._MultiPath__map = None
        self._MultiPath__parts = []

        # this sets the refcount to 1 (undone by __del__)
        self._MultiPath__name = nameCache.new()

        self.active = False
        self.mknod = False

        self.bdevs = []
        if bdevs:
            self.checkBdevs(bdevs)

        table = self.get_table()
        import dm as _dm

        self.get_map()
        # this sets the refcount to 2 (undone by __deactivate__)
        nameCache.get(self.name)

    def __del__(self):
        if not nameCache[self.name] in [1, 2]:
            raise RuntimeError, "%s has refcount %s on __del__" % (self.name, 
                nameCache[self.name])
        nameCache.put(self.name)

    def firstDevPath(self):
            l = list(self.member_devpaths)
            l.sort()
            return l[0]

    def __cmp__(self, other):
        s = self.firstDevPath()
        o = other.firstDevPath()
        if s < o:
            return -1
        elif s == o:
            return cmp(self.map, other.map)
        return 1

    def checkBdevs(self, bdevs):
        bdh = {}
        for x in self.bdevs:
            bdh[x] = None
        for bdev in bdevs:
            if not bdh.has_key(bdev):
                self.bdevs.append(bdev)

        import os as _os
        self.size = None
        rdevs = {}
        for bdev in self.bdevs:
            sb = _os.stat(bdev)
            rdev = sb.st_rdev
            if rdevs.has_key(rdev):
                continue
            rdevs[rdev] = 1
                
            sysfile = '/sys/block/%s/size' % (bdev.split('/')[-1],)
            f = open(sysfile)
            size = f.readlines()[0]
            del f
            size = int(size.strip())

            if self.size is None:
                self.size = size
            if self.size != size:
                raise ValueError, "mismatched sizes"
        del _os

    def get_prefix(self):
        return self._MultiPath__prefix
    def set_prefix(self, value):
        self._MultiPath__prefix = value
    prefix = property(get_prefix, set_prefix, None, \
        "prefix for path to device nodes")

    def _set_map_uuid(self, map):
        if map and not map.uuid:
            map.uuid = "MPATH-%s" % map.name
        
    def get_PedDevice(self):
        import parted as _parted
        ret = _parted.getDevice(self.bdev.path)
        del _parted
        return ret
    PedDevice = property(get_PedDevice, None, None, "parted.PedDevice")

    def get_members(self, descend=True):
        for bdev in self.bdevs:
            yield bdev
    members = property(get_members, None, None, "members")

    def get_member_devpaths(self, descend=True):
        for m in self.get_members(descend):
            if str(m).startswith("/dev/"):
                yield str(m)
            else:
                yield "/dev/" + m
    member_devpaths = property(get_member_devpaths, None, None, "member devpaths")
    def get_bdev(self):
        if not self._MultiPath__bdev is None:
            return self._MultiPath__bdev
        try:
            self._MultiPath__bdev = BlockDev(self.prefix + self.name)
            return self._MultiPath__bdev
        except:
            raise
            pass
    bdev = property(get_bdev, None, None, "block.BlockDev")

    def get_table(self):
        if not self._MultiPath__table is None:
            return self._MultiPath__table

        # we get "/dev/hda" from one and "3:0" from the other, so we have to
        # fix up the device name
        def munge_dev(path):
            if path[0] != '/':
                return path.strip()

            bd = map_dev(path)
            # starting with 2.6.17-1.2510.fc6 or so, there's an implicit
            # minimum IOs of 1000, which gets _added_ to the line "dmsetup ls"
            # shows.  This sucks.
            return "%s 1000" % (bd,)

        tableParts = [0, self.size, 'multipath']
        
        params = '0 0 1 1 round-robin 0 %s 1 %s' % (len(self.bdevs), \
                        _string.join(map(munge_dev, self.bdevs)))
        tableParts.append(params)

        import dm as _dm
        table = apply(_dm.table, tableParts, {})
        del _dm

        self._MultiPath__table = [ table ]
        return self._MultiPath__table
    table = property(get_table, None, None, "block.dm.table")

    def get_map(self):
        if not self._MultiPath__map is None:
            return self._MultiPath__map

        table = self.get_table()

        import dm as _dm

        for map in _dm.maps():
            if compare_tables(map.table, table):
                if self.name != map.name:
                    self.name = nameCache.rename(self.name, map.name)

                self._MultiPath__map = map
                self.buildParts()
                self.active = True
                del _dm
                return self._MultiPath__map

        # all else has failed, make a new map...
        self._MultiPath__map = _dm.map(name=self.name, table=table)
        self.buildParts()
        self.active = True
        del _dm
        return self._MultiPath__map
    map = property(get_map, None, None, "block.dm.map")

    def get_name(self):
        return self._MultiPath__name
    def set_name(self, name):
        bdev = self._MultiPath__bdev
        prefix = self.prefix

        self.deactivate()
        self._MultiPath__name = nameCache.rename(self._MultiPath__name, name)
        self._MultiPath__bdev = BlockDev().FromMajorMinor(bdev.major, bdev.minor)
        self.bdev.mode = 0600
        self.bdev.path = prefix + name
        self.activate()
    name = property(get_name, set_name, None, "the name of this MultiPath")

    def get_parts(self):
        if self._MultiPath__parts is None:
            self.buildParts()
        for x in self._MultiPath__parts:
            yield x
    partitions = property(get_parts, None, None, "this device's partitions")

    def output(self, *args):
        for x in args:
            print x

    def buildPartMaps(self):
        from maps import PartitionDeviceMap as _PartitionDeviceMap
        import parted as _parted
        import _ped

        dev = self.PedDevice
        dev.open()
        try:
            disk = _parted.Disk(dev)
        except (_ped.DiskLabelException,_parted.DiskException), msg:
            dev.close()
            del dev
            return

        for part in disk.partitions:
            if part.active:
                name = "%sp%s" % (self.name, part.number)
                bdev = BlockDev(self.prefix + self.name)
                bdev.mode = 0600
                if part.type != _parted.PARTITION_EXTENDED:
                    map = _PartitionDeviceMap(0, part.geometry.length, bdev,
                        part.geometry.start, part.number)
                else:
                    # special mapping for extended partitions see the comment
                    # in RaidSet.buildPartMaps()
                    map = _PartitionDeviceMap(0, 2, bdev,
                        part.geometry.start, part.number)
                map.name = name
                self._set_map_uuid(map)
                yield map

        del disk
        dev.close()
        del dev
        del _PartitionDeviceMap
        del _parted
        del _ped

    def buildParts(self):
        import dm as _dm

        maps = self.buildPartMaps()
        for map in maps:
            map.create()
            self._MultiPath__parts.append(map)

    def removeMemberParts(self):
        import dm as _dm
        for x in range(1,257):
            for m in self.member_devpaths:
                _dm.rmpart(m, x)
        del _dm

    def scanMemberParts(self):
        import dm as _dm
        for m in self.member_devpaths:
            _dm.scanparts(m)
        del _dm

    def activate(self, mknod=False):
        if self.active:
            return
        if mknod:
            try:
                _os.unlink(self.prefix+self.name)
            except:
                pass
            self.map.dev.mknod(self.prefix+self.name)
            self.mknod = True

        self._set_map_uuid(self.map)
        nameCache.get(self.name) # this should set the refcount to 2

        self.removeMemberParts()
        self.buildParts()
        ret = self.partitions
        return ret

    def deactivate(self):
        if not self.active:
            return
        parts = self._MultiPath__parts
        self._MultiPath__parts = []
        for part in parts:
            try:
                part.map.remove()
            except:
                pass
        parts = list(self.partitions)
        if len(parts) == 0 and not self._MultiPath__map is None:
            removeDeviceMap(self._MultiPath__map)
            self._MultiPath__map = None
            self.active = False
            nameCache.put(self.name) # this should take the refcount to 1
        elif len(parts) > 0:
            raise RuntimeError, "multipath has active partitions"
        self.scanMemberParts()

    def display(self, space=0, printer=lambda x,y: _sys.stdout.write("%s%s\n" % (x*' ',y))):
        printer(space, self)
        for m in self.members:
            m.display(space+1, printer=printer)

class RaidSet:
    def __init__(self, rs, prefix="/dev/mapper/"):
        self.rs = rs
        self._RaidSet__prefix = prefix
        self._RaidSet__bdev = None
        self._RaidSet__map = None
        self._RaidSet__parts = []
        self._RaidSet__name = rs.name
        self._RaidSet__activeMembers = []
        self.active = False
        self.mknod = False

    def __cmp__(self, other):
        return cmp(self.map, other.map)

    def get_prefix(self):
        return self._RaidSet__prefix
    def set_prefix(self, value):
        self._RaidSet__prefix = value
    prefix = property(get_prefix, set_prefix, None, \
        "prefix for path to device nodes")
        
    def _set_map_uuid(self, map):
        if map and not map.uuid:
            # make sure the map has a uuid complete with subsystem prefix
            map.uuid = "DMRAID-%s" % map.name

    def get_PedDevice(self):
        import parted as _parted
        ret = _parted.getDevice(self.bdev.path)
        del _parted
        return ret
    PedDevice = property(get_PedDevice, None, None, "parted.PedDevice")

    def get_level(self):
        # We do not handle layered raid properly here, nor raid5 nor JBOD
        raise NotImplementedError, "FIXME"
        if self.rs.dmtype in ("stripe", "striped"):
            return 0
        elif self.rs.dmtype == "mirror":
            return 1
        raise NotImplementedError, "unknown dmtype %s" % (self.rs.dmtype,)
    level = property(get_level, None, None, "raid level")

    def get_members(self, descend=True):
        import dmraid as _dmraid

        for c in self.rs.children:
            if isinstance(c, _dmraid.raidset):
                r = RaidSet(c, prefix=self.prefix)
                yield r
                if descend:
                    for m in r.members:
                        yield m
            elif isinstance(c, _dmraid.raiddev):
                yield RaidDev(c)

        del _dmraid

    members = property(get_members, None, None, "members")

    def get_member_devpaths(self, descend=True):
        for m in self.get_members(descend):
            if isinstance(m, RaidDev):
                yield m.devpath
    member_devpaths = property(get_member_devpaths, None, None, "member devpaths")

    def get_spares(self, descend=True):
        import dmraid as _dmraid

        for s in self.rs.spares:
            if isinstance(c, _dmraid.raidset):
                r = RaidSet(c)
                yield r
                if descend:
                    for m in r.members:
                        yield m
                    for m in r.spares:
                        yield m
            elif isinstance(c, _dmraid.raiddev):
                yield RaidDev(c)
        # members might have spares as well
        for c in self.rs.children:
            if isinstance(c, _dmraid.raidset) and descend:
                for spare in RaidSet(c).spares:
                    yield spare

        del _dmraid
    spares = property(get_spares, None, None, "spares")

    def get_bdev(self):
        if not self._RaidSet__bdev is None:
            return self._RaidSet__bdev
        try:
            self._RaidSet__bdev = BlockDev(self.prefix + self.name)
            return self._RaidSet__bdev
        except:
            pass
    bdev = property(get_bdev, None, None, "block.BlockDev")

    def get_map(self):
        if not self._RaidSet__map is None:
            return self._RaidSet__map

        import dm as _dm

        for map in _dm.maps():
            if compare_tables(map.table, self.rs.dmTable):
                self._RaidSet__map = map
                self.active = True
                del _dm
                return self._RaidSet__map

        # all else has failed, make a new map...
        self._RaidSet__map = _dm.map(name=self.name, table=self.rs.dmTable)
        self.active = True
        del _dm
        return self._RaidSet__map
    map = property(get_map, None, None, "block.dm.map")

    def get_name(self):
        return self._RaidSet__name
    def set_name(self, name):
        bdev = self._RaidSet__bdev
        prefix = self.prefix

        self.deactivate()
        self.rs.name = name
        self._RaidSet__name = name
        self._RaidSet__bdev = BlockDev().FromMajorMinor(bdev.major, bdev.minor)
        self.bdev.mode = 0600
        self.bdev.path = prefix + name
        self.activate()

    name = property(get_name, set_name, None, "this name of this RaidSet")

    def get_parts(self):
        for x in self._RaidSet__parts:
            yield x
    partitions = property(get_parts, None, None, "this device's partitions")

    def get_valid(self):
        if self.rs.broken:
            return False
        if self.rs.degraded:
            return False
        for x in self.members:
            if isinstance(x, RaidDev) or isinstance(x, RaidSet):
                if not x.valid:
                    return False
        return True
    valid = property(get_valid, None, None, "test a raidset for validity")

    def output(self, *args):
        for x in args:
            print x

    def buildParts(self):
        from maps import PartitionDeviceMap as _PartitionDeviceMap
        import parted as _parted
        import _ped

        dev = self.PedDevice
        dev.open()
        try:
            disk = _parted.Disk(device=dev)
        except (_ped.DiskLabelException,
                        _parted.DiskException,_parted.IOException), msg:
            dev.close()
            del dev
            return

        for part in disk.partitions:
            if part.active:
                name = "%sp%s" % (self.name, part.number)
                bdev = BlockDev(self.prefix + self.name)
                bdev.mode = 0600
                if part.type != _parted.PARTITION_EXTENDED:
                    map = _PartitionDeviceMap(0, part.geometry.length, bdev,
                        part.geometry.start, part.number)
                else:
                    # Various tools create different mappings for ext. parts:
                    # dmraid: Does not create a mapping for extended parts
                    # kpartx: Creates a mapping with a size of 2 sectors
                    # parted: Creates a mapping with the actual partition size
                    #
                    # The kernel does the same as kpartx for regular disks.
                    # We do as kpartx and create a 2 sector mapping, so that if
                    # there is a pre-existing mapping (ie a livecd install), we
                    # recognize it and don't try to create one.
                    map = _PartitionDeviceMap(0, 2, bdev,
                        part.geometry.start, part.number)
                map.name = name
                self._set_map_uuid(map)
                map.create()
                self._RaidSet__parts.append(map)

        del disk
        dev.close()
        del dev
        del _PartitionDeviceMap
        del _parted
        del _ped

    def removeMemberParts(self):
        for m in self.members:
            if isinstance(m, RaidDev):
                m.removeParts()
            elif isinstance(m, RaidSet):
                m.removeMemberParts()

    def scanMemberParts(self):
        for m in self.members:
            if isinstance(m, RaidDev):
                m.scanParts()
            elif isinstance(m, RaidSet):
                m.scanMemberParts()

    def activate(self, degradedOk=False, mknod=False, mkparts=True):
        if self.active:
            return

        # We put the active members in a list so we can deactivate them later.
        for member in self.members:
            if isinstance(member, RaidSet):
                member.activate(degradedOk=degradedOk, mknod=mknod, mkparts=False)
                self._RaidSet__activeMembers.append(member)

        if mknod:
            try:
                _os.unlink(self.prefix+self.name)
            except:
                pass
            self.map.dev.mknod(self.prefix+self.name)
            self.mknod = True
            self._set_map_uuid(self.map)

        self.removeMemberParts()
        if mkparts:
            self.buildParts()
        ret = self.partitions
        return ret

    def deactivate(self):
        if not self.active:
            return
        parts = self._RaidSet__parts
        self._RaidSet__parts = []
        for part in parts:
            try:
                part.map.remove()
            except:
                pass
        parts = list(self.partitions)
        if len(parts) == 0 and not self._RaidSet__map is None:
            removeDeviceMap(self._RaidSet__map)
            self._RaidSet__map = None
            self.active = False
        elif len(parts) > 0:
            raise RuntimeError, "raidset has active partitions"

        for activeMember in self._RaidSet__activeMembers:
            activeMember.deactivate()
        self._RaidSet__activeMembers = []

        self.scanMemberParts()

    def display(self, space=0, printer=lambda x,y: _sys.stdout.write("%s%s\n" % (x*' ',y))):
        printer(space, self)
        for m in self.members:
            m.display(space+1, printer=printer)

class RaidDev:
    def __init__(self, rd, prefix=None):
        self.rd = rd
        self._RaidDev__bdev = None
        self._RaidDev__prefix = None

    def get_prefix(self):
        if self._RaidDev__prefix is None:
            self._RaidDev__prefix = \
                _string.join(self.rd.device.path.split('/')[:-1],'/') + '/'
        return self._RaidDev__prefix
    prefix = property(get_prefix, None, None, "prefix for device node path")

    def get_bdev(self):
        if self._RaidDev__bdev is None:
            bdev = BlockDev().FromFile(self.rd.device.path)
            self._RaidDev__bdev = bdev
        return self._RaidDev__bdev
    bdev = property(get_bdev, None, None, "block.BlockDev")

    def get_PedDevice(self):
        import parted as _parted
        ret = _parted.getDevice(self.bdev.path)
        del _parted
        return ret
    PedDevice = property(get_PedDevice, None, None, "parted.PedDevice")

    def get_devpath(self):
        return self.rd.device.path.split('/')[-1]
    devpath = property(get_devpath, None, None, "path relative to /dev")

    def get_valid(self):
        if self.bdev is not None and \
                hasattr(self.bdev, 'path') and self.bdev.path is not None:
            return True
        return False
    valid = property(get_valid, None, None, "test a raiddev for validity")

    def __cmp__(self, other):
        # Dear Python, you are retarded.
        def strcmp(a,b):
            ab = zip(reduce(lambda x,y: x + [ord(y)], list(a), []),
                reduce(lambda x,y: x + [ord(y)], list(b), []))
            cmps = filter(None, map(lambda (x,y): cmp(x,y), ab)) or \
                [len(a) - len(b),]
            return cmps[0]

        obdev = other
        if isinstance(other, "".__class__):
            filename = '/dev/' + other
            if other[0].isdigit():
                maj,min = (0,0)
                if ':' in other:
                    maj,min = other.split(':')[0:2]
                    obdev = BlockDev().FromMajorMinor(maj,min)
                else:
                    device = str(self.bdev.device)
                    return strcmp(device, other)
            elif other.startswith("/"):
                try:
                    obdev = BlockDev().FromFile(other)
                except:
                    filename = self.devpath
            elif other.startswith('/dev/mapper/'):
                filename = '/dev/mapper/' + self.devpath
            elif other.startswith('/dev/'):
                filename = '/dev/' + self.devpath
            elif other.startswith('/tmp/'):
                filename = '/tmp/' + self.devpath

            try:
                obdev = BlockDev().FromFile(filename)
            except:
                return strcmp(filename, other)

        if isinstance(obdev, BlockDev):
            try:
                return cmp(self.bdev.device.dev, obdev.device.dev)
            except:
                pass

        elif isinstance(other, RaidDev):
            if self.rd.device.serial is not None and \
                    other.rd.device.serial is not None:
                return strcmp(self.rd.device.serial, other.rd.device.serial)

            elif self.bdev is not None and other.bdev is not None:
                return strcmp(self.bdev.device.dev, other.bdev.device.dev)

            else:
                return strcmp(self.devpath, other.devpath)
        return -1 

    def removeParts(self):
        for x in range(1,257):
            self.rd.device.rmpart(x)

    def scanParts(self):
        self.rd.device.scanparts()

    def display(self, space=0, printer=lambda x,y: _sys.stdout.write("%s%s\n" % (x*' ',y))):
        printer(space, self)

#
# vim:ts=8:sts=4:sw=8:et
#