new approach for blockdevice detection and handling
This commit is contained in:
parent
cbfddddeb2
commit
53e09ff825
1 changed files with 230 additions and 0 deletions
230
src/cryptobox/core/blockdevice.py
Normal file
230
src/cryptobox/core/blockdevice.py
Normal file
|
@ -0,0 +1,230 @@
|
|||
#
|
||||
# Copyright 2007 sense.lab e.V.
|
||||
#
|
||||
# This file is part of the CryptoBox.
|
||||
#
|
||||
# The CryptoBox 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) any later version.
|
||||
#
|
||||
# The CryptoBox 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 the CryptoBox; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
'''
|
||||
These classes detect and filter available blockdevices.
|
||||
'''
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
|
||||
"""
|
||||
TODO:
|
||||
- implement some caching
|
||||
- find the devnodes for each device (e.g. /dev/hda)
|
||||
- detect luks devices
|
||||
- detect LVM
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
|
||||
class Blockdevices:
|
||||
|
||||
def __init__(self, sysblock_dir='/sys/block', devnode_dir='/dev'):
|
||||
self.sysblock_dir = sysblock_dir
|
||||
self.devnode_dir = devnode_dir
|
||||
self.devices = []
|
||||
for devdir in find_blockdevices(self.sysblock_dir):
|
||||
blockdevice = Blockdevice(devdir, self.devnode_dir)
|
||||
if not blockdevice is None:
|
||||
self.devices.append(blockdevice)
|
||||
|
||||
|
||||
def get_devices(self):
|
||||
"""return a copy of the device list
|
||||
"""
|
||||
return self.devices[:]
|
||||
|
||||
|
||||
|
||||
|
||||
class Blockdevice:
|
||||
|
||||
def __init__(self, dev, devnode_dir='/dev', sysblock_dir='/sys/block'):
|
||||
self.devnode_dir = devnode_dir
|
||||
self.sysblock_dir = sysblock_dir
|
||||
if os.path.isabs(dev):
|
||||
self.devdir = dev
|
||||
else:
|
||||
self.devdir = self.__find_relative_device(dev)
|
||||
if self.devdir is None:
|
||||
self = None
|
||||
return
|
||||
self.name = os.path.basename(self.devdir)
|
||||
self.devnum = self.__get_major_minor()
|
||||
## check valid devnum
|
||||
try:
|
||||
major, minor = self.devnum
|
||||
except TypeError:
|
||||
self = None
|
||||
return
|
||||
self.size = self.__get_size()
|
||||
self.range = self.__get_device_range()
|
||||
self.slaves = self.__get_dev_related("slaves")
|
||||
self.holders = self.__get_dev_related("holders")
|
||||
self.children = self.__get_children()
|
||||
|
||||
|
||||
def isstorage(self):
|
||||
if self.range > 1:
|
||||
## partitionable blockdevice
|
||||
return False
|
||||
if self.size < 20:
|
||||
## extended partition, unused loop device
|
||||
return False
|
||||
if self.devnum[0] == 1:
|
||||
## ram device
|
||||
return False
|
||||
if self.children:
|
||||
## a parent blockdevice
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def ispartitionable(self):
|
||||
if self.range > 1:
|
||||
return True
|
||||
|
||||
|
||||
def __find_relative_device(self, devname):
|
||||
for devdir in find_blockdevices(self.sysblock_dir):
|
||||
if os.path.basename(devdir) == devname:
|
||||
return devdir
|
||||
return None
|
||||
|
||||
|
||||
def __get_dev_related(self, subdir):
|
||||
"""return the content of sub directories (e.g. 'holders' or 'slaves')
|
||||
"""
|
||||
try:
|
||||
return os.listdir(os.path.join(self.devdir, subdir))
|
||||
except OSError:
|
||||
return []
|
||||
|
||||
|
||||
def __get_size(self):
|
||||
default = 0
|
||||
try:
|
||||
return int(file(os.path.join(self.devdir, 'size')).read())
|
||||
except OSError:
|
||||
return default
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
def __get_major_minor(self):
|
||||
"""return the major and minor of the device"""
|
||||
default = (0 ,0)
|
||||
try:
|
||||
content = file(os.path.join(self.devdir, "dev")).read()
|
||||
except IOError:
|
||||
return default
|
||||
major, minor = content.split(":", 2)
|
||||
try:
|
||||
return int(major), int(minor)
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
def __get_device_range(self):
|
||||
"""number of possible subdevices
|
||||
|
||||
partitionable blockdevices have a range > 1
|
||||
"""
|
||||
default = 1
|
||||
try:
|
||||
content = file(os.path.join(self.devdir, "range")).read()
|
||||
except IOError:
|
||||
return default
|
||||
try:
|
||||
return int(content)
|
||||
except ValueError:
|
||||
return default
|
||||
|
||||
|
||||
def __get_children(self):
|
||||
"""return all devices depending on the current one
|
||||
|
||||
all holders, subdevices and children of subdevices
|
||||
"""
|
||||
direct_children = [Blockdevice(child).name
|
||||
for child in find_blockdevices(self.devdir)]
|
||||
direct_children.extend(self.holders[:])
|
||||
children = direct_children[:]
|
||||
for dchild in direct_children:
|
||||
children.extend(Blockdevice(dchild).children)
|
||||
return children
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
def info(self):
|
||||
output = "%s:\n" % self.name
|
||||
output += "\t%s:\t%s\n" % ("blockdir", self.devdir)
|
||||
output += "\t%s:\t%s\n" % ("major/minor", self.devnum)
|
||||
output += "\t%s:\t\t%s\n" % ("range", self.range)
|
||||
output += "\t%s:\t\t%s\n" % ("size", self.size)
|
||||
output += "\t%s:\t\t%s\n" % ("slaves", self.slaves)
|
||||
output += "\t%s:\t%s\n" % ("holders", self.holders)
|
||||
output += "\t%s:\t%s\n" % ("children", self.children)
|
||||
return output
|
||||
|
||||
|
||||
|
||||
def find_blockdevices(top_dir):
|
||||
|
||||
dev_dirs = []
|
||||
|
||||
def look4dev_dirs(arg, dirname, fnames):
|
||||
## ignore the top level directory to avoid infinite recursion for
|
||||
## get_children
|
||||
if os.path.samefile(dirname, top_dir):
|
||||
return
|
||||
## add directories containing the file 'dev' to the list
|
||||
if (arg in fnames) and os.path.isfile(os.path.join(dirname, arg)):
|
||||
dev_dirs.append(dirname)
|
||||
for fname in fnames:
|
||||
## remove symlinks and non-directories
|
||||
fullname = os.path.join(dirname, fname)
|
||||
if os.path.islink(fullname) or (not os.path.isdir(fullname)):
|
||||
fnames.remove(fname)
|
||||
|
||||
os.path.walk(top_dir, look4dev_dirs, 'dev')
|
||||
return dev_dirs
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
blocks = Blockdevices()
|
||||
for dev in blocks.get_devices():
|
||||
print dev.info()
|
||||
print
|
||||
print "Usable storage devices:"
|
||||
for dev in blocks.get_devices():
|
||||
if dev.isstorage():
|
||||
print dev
|
||||
print
|
||||
print "Partitionable devices:"
|
||||
for dev in blocks.get_devices():
|
||||
if dev.ispartitionable():
|
||||
print dev
|
||||
|
Loading…
Reference in a new issue