adapt partition plugin to the new blockdevice implementation

reduce minimum storage block size from 20 to 10 (the config partition is small)
This commit is contained in:
lars 2007-09-11 10:22:48 +00:00
parent 4a4778d876
commit 9c649312d0
5 changed files with 143 additions and 301 deletions

View file

@ -27,7 +27,7 @@ import subprocess
import os import os
import re import re
import logging import logging
import cryptobox.core.tools as cbox_tools import cryptobox.core.blockdevice as blockdevice_tools
import cryptobox.plugins.base import cryptobox.plugins.base
from cryptobox.core.exceptions import * from cryptobox.core.exceptions import *
@ -58,15 +58,19 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
self.__prepare_dataset() self.__prepare_dataset()
## retrieve some values from 'args' - defaults are empty ## retrieve some values from 'args' - defaults are empty
self.blockdevice = self.__get_selected_device(args) self.blockdevice = self.__get_selected_device(args)
self.with_config_partition = self.__is_with_config_partition() if self.blockdevice:
self.with_config_partition = self.__is_with_config_partition()
self.blockdevice_size = self.__get_available_device_size(self.blockdevice)
else:
self.with_config_partition = False
self.blockdevice_size = 0
self.cbox.log.debug( self.cbox.log.debug(
"partition plugin: selected device=%s" % str(self.blockdevice)) "partition plugin: selected device=%s" % str(self.blockdevice))
self.blockdevice_size = self.__get_available_device_size(self.blockdevice)
## no (or invalid) device was supplied ## no (or invalid) device was supplied
if not self.blockdevice: if not self.blockdevice:
return self.__action_select_device() return self.__action_select_device()
## exit if the blockdevice is not writeable ## exit if the blockdevice is not writeable
if not os.access(self.blockdevice, os.W_OK): if not os.access(self.blockdevice.devnodes[0], os.W_OK):
self.hdf["Data.Warning"] = "DeviceNotWriteable" self.hdf["Data.Warning"] = "DeviceNotWriteable"
return self.__action_select_device() return self.__action_select_device()
## no confirm setting? ## no confirm setting?
@ -91,15 +95,19 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
"partition: invalid partition number to delete (%s)" % del_args[0]) "partition: invalid partition number to delete (%s)" % del_args[0])
return self.__action_select_device() return self.__action_select_device()
return self.__action_del_partition(args, num_part) return self.__action_del_partition(args, num_part)
else: # for "select_device" and for invalid targets else:
## for "select_device" and for invalid targets
return self.__action_select_device() return self.__action_select_device()
def get_status(self): def get_status(self):
"""The status of this plugin is the selected device and some information. """The status of this plugin is the selected device and some information.
""" """
return "%s / %s / %s" % (self.blockdevice, self.blockdevice_size, if not self.blockdevice:
self.with_config_partition) return "no blockdevice selected"
else:
return "%s / %s / %s" % (self.blockdevice.name,
self.blockdevice_size, self.with_config_partition)
def get_warnings(self): def get_warnings(self):
@ -131,7 +139,13 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
"""Check the selected device (valid, not busy, ...). """Check the selected device (valid, not busy, ...).
""" """
try: try:
blockdevice = args["block_device"] blockdevice_name = args["block_device"]
found = [ dev for dev in
blockdevice_tools.Blockdevices().get_partitionable_devices()
if dev.name == blockdevice_name ]
if not found:
return None
blockdevice = found[0]
except KeyError: except KeyError:
return None return None
if not self.__is_device_valid(blockdevice): if not self.__is_device_valid(blockdevice):
@ -149,8 +163,6 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
return False return False
if not self.cbox.is_device_allowed(blockdevice): if not self.cbox.is_device_allowed(blockdevice):
return False return False
if not blockdevice in cbox_tools.get_parent_blockdevices():
return False
return True return True
@ -158,9 +170,10 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
"""check if the device (or one of its partitions) is mounted """check if the device (or one of its partitions) is mounted
""" """
## the config partition is ignored, as it will get unmounted if necessary ## the config partition is ignored, as it will get unmounted if necessary
for cont in self.cbox.get_container_list(): for dev in blockdevice.children:
if cbox_tools.is_part_of_blockdevice(blockdevice, cont.get_device()) \ container = self.cbox.get_container(
and cont.is_mounted(): blockdevice_tools.get_blockdevice(dev).devnodes[0])
if container and (container.is_mounted() or container.is_busy()):
return True return True
return False return False
@ -168,15 +181,17 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
def __action_select_device(self): def __action_select_device(self):
"""Show a form to select the device for partitioning. """Show a form to select the device for partitioning.
""" """
block_devices = [e block_devices = [ e for e in
for e in cbox_tools.get_parent_blockdevices() blockdevice_tools.Blockdevices().get_partitionable_devices()
if self.cbox.is_device_allowed(e)] if self.cbox.is_device_allowed(e) ]
counter = 0 counter = 0
for dev in block_devices: for dev in block_devices:
self.hdf[self.hdf_prefix + "BlockDevices.%d.name" % counter] = dev self.hdf[self.hdf_prefix + "BlockDevices.%d.name" % counter] = \
dev.name
self.hdf[self.hdf_prefix + "BlockDevices.%d.size" % counter] = \ self.hdf[self.hdf_prefix + "BlockDevices.%d.size" % counter] = \
cbox_tools.get_blockdevice_size_humanly(dev) dev.size_human
self.cbox.log.debug("found a suitable block device: %s" % dev) self.cbox.log.debug("found a suitable block device: %s" % \
dev.devnodes[0])
counter += 1 counter += 1
if self.with_config_partition: if self.with_config_partition:
self.hdf[self.hdf_prefix + "CreateConfigPartition"] = "1" self.hdf[self.hdf_prefix + "CreateConfigPartition"] = "1"
@ -189,7 +204,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
def __action_add_partition(self, args): def __action_add_partition(self, args):
"""Add a selected partition to the currently proposed partition table. """Add a selected partition to the currently proposed partition table.
""" """
self.hdf[self.hdf_prefix + "Device"] = self.blockdevice self.hdf[self.hdf_prefix + "Device"] = self.blockdevice.name
self.hdf[self.hdf_prefix + "Device.Size"] = self.blockdevice_size self.hdf[self.hdf_prefix + "Device.Size"] = self.blockdevice_size
parts = self.__get_partitions_from_args(args) parts = self.__get_partitions_from_args(args)
self.__set_partition_data(parts) self.__set_partition_data(parts)
@ -199,7 +214,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
def __action_del_partition(self, args, part_num): def __action_del_partition(self, args, part_num):
"""Remove a partition from the proposed partition table. """Remove a partition from the proposed partition table.
""" """
self.hdf[self.hdf_prefix + "Device"] = self.blockdevice self.hdf[self.hdf_prefix + "Device"] = self.blockdevice.name
self.hdf[self.hdf_prefix + "Device.Size"] = self.blockdevice_size self.hdf[self.hdf_prefix + "Device.Size"] = self.blockdevice_size
parts = self.__get_partitions_from_args(args) parts = self.__get_partitions_from_args(args)
## valid partition number to be deleted? ## valid partition number to be deleted?
@ -215,8 +230,11 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
parts = self.__get_partitions_from_args(args) parts = self.__get_partitions_from_args(args)
if parts: if parts:
self.__set_partition_data(parts) self.__set_partition_data(parts)
if cbox_tools.is_part_of_blockdevice(self.blockdevice, ## umount config partition if necessary
self.cbox.prefs.get_active_partition()): config_partition = self.cbox.prefs.get_active_partition()
if [ dev for dev in self.blockdevice.children
if config_partition in
blockdevice_tools.get_blockdevice(dev).devnodes ]:
self.cbox.prefs.umount_partition() self.cbox.prefs.umount_partition()
if not self.__run_fdisk(parts): if not self.__run_fdisk(parts):
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed" self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
@ -257,9 +275,10 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
format_ok = False format_ok = False
if format_ok: if format_ok:
self.hdf["Data.Success"] = "Plugins.partition.Partitioned" self.hdf["Data.Success"] = "Plugins.partition.Partitioned"
return { "plugin":"system_preferences", "values":[] }
else: else:
self.hdf["Data.Warning"] = "Plugins.partition.FormattingFailed" self.hdf["Data.Warning"] = "Plugins.partition.FormattingFailed"
return "empty" return "empty"
else: else:
return self.__action_add_partition(args) return self.__action_add_partition(args)
@ -270,15 +289,17 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
import types import types
## we do not have to take special care for a possible config partition ## we do not have to take special care for a possible config partition
parts = [ { "size": self.blockdevice_size, "type": "windows" } ] parts = [ { "size": self.blockdevice_size, "type": "windows" } ]
## umount partition if necessary ## umount config partition if necessary
if cbox_tools.is_part_of_blockdevice(self.blockdevice, config_partition = self.cbox.prefs.get_active_partition()
self.cbox.prefs.get_active_partition()): if [ dev for dev in self.blockdevice.children
if config_partition in
blockdevice_tools.get_blockdevice(dev).devnodes ]:
self.cbox.prefs.umount_partition() self.cbox.prefs.umount_partition()
## partition it ## partition it
if not self.__run_fdisk(parts): if not self.__run_fdisk(parts):
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed" self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
return None return None
## "formatPartitions" is a generator, returning device names and bolean values ## "formatPartitions" is a generator, returning device names and boolean values
result = [e for e in self.__format_partitions(parts) result = [e for e in self.__format_partitions(parts)
if type(e) == types.BooleanType] if type(e) == types.BooleanType]
if self.with_config_partition: if self.with_config_partition:
@ -317,11 +338,12 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
for ptype in PARTTYPES.keys(): for ptype in PARTTYPES.keys():
self.hdf[self.hdf_prefix + "Types.%s" % ptype] = ptype self.hdf[self.hdf_prefix + "Types.%s" % ptype] = ptype
## store the currently existing partitions of the choosen block device ## store the currently existing partitions of the choosen block device
current_containers = [ e for e in self.cbox.get_container_list() current_containers = [ blockdevice_tools.get_blockdevice(dev)
if cbox_tools.is_part_of_blockdevice(self.blockdevice, e.get_device()) ] for dev in self.blockdevice.children
if blockdevice_tools.get_blockdevice(dev).is_storage() ]
for (index, cont) in enumerate(current_containers): for (index, cont) in enumerate(current_containers):
self.hdf[self.hdf_prefix + "ExistingContainers.%d" % index] = \ self.hdf[self.hdf_prefix + "ExistingContainers.%d" % index] = \
cont.get_device() cont.name
def __get_partitions_from_args(self, args): def __get_partitions_from_args(self, args):
@ -361,11 +383,11 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
"""calculate the available size (MB) of the device """calculate the available size (MB) of the device
also consider a (possible) configuration partition also consider a (possible) configuration partition
""" """
device_size = cbox_tools.get_blockdevice_size(device) device_size = device.size
if device_size < 0:
return 0
if self.with_config_partition: if self.with_config_partition:
device_size -= CONFIGPARTITION["size"] device_size -= CONFIGPARTITION["size"]
if device_size < 0:
return 0
return device_size return device_size
@ -378,7 +400,12 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
if not active: if not active:
return True return True
## check if the active one is part of the current device ## check if the active one is part of the current device
return cbox_tools.is_part_of_blockdevice(self.blockdevice, active) if [ dev for dev in self.blockdevice.children
if active in
blockdevice_tools.get_blockdevice(dev).devnodes ]:
return True
else:
return False
return False return False
@ -402,7 +429,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
"plugin", "plugin",
os.path.join(self.plugin_dir, "root_action.py"), os.path.join(self.plugin_dir, "root_action.py"),
"partition", "partition",
self.blockdevice]) self.blockdevice.devnodes[0]])
for line in self.__get_sfdisk_layout(parts, is_filled): for line in self.__get_sfdisk_layout(parts, is_filled):
proc.stdin.write(line + "\n") proc.stdin.write(line + "\n")
#TODO: if running inside of an uml, then sfdisk hangs at "nanosleep({3,0})" #TODO: if running inside of an uml, then sfdisk hangs at "nanosleep({3,0})"
@ -455,22 +482,22 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
part_num = 1 part_num = 1
## maybe a config partition? ## maybe a config partition?
if self.with_config_partition: if self.with_config_partition:
dev_name = self.__get_partition_name(self.blockdevice, part_num) dev_name = self.__get_partition_device(self.blockdevice, part_num)
self.cbox.log.info("formatting config partition (%s)" % dev_name) self.cbox.log.info("formatting config partition (%s)" % dev_name)
if self.__format_one_partition(dev_name, CONFIGPARTITION["fs"]): if self.__format_one_partition(dev_name, CONFIGPARTITION["fs"]):
self.__set_label_of_partition(dev_name, self.__set_label_of_partition(dev_name,
self.cbox.prefs["Main"]["ConfigVolumeLabel"]) self.cbox.prefs["Main"]["ConfigVolumeLabel"])
part_num += 1 part_num += 1
## the first data partition ## the first data partition
dev_name = self.__get_partition_name(self.blockdevice, part_num) dev_name = self.__get_partition_device(self.blockdevice, part_num)
part_type = PARTTYPES[parts[0]["type"]][1] part_type = PARTTYPES[parts[0]["type"]][1]
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, part_type)) self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, part_type))
yield self.__format_one_partition(dev_name, part_type) yield self.__format_one_partition(dev_name, part_type)
del parts[0] del parts[0]
## other data partitions ## other data partitions
part_num = 5 part_num += 1
while parts: while parts:
dev_name = self.__get_partition_name(self.blockdevice, part_num) dev_name = self.__get_partition_device(self.blockdevice, part_num)
part_type = PARTTYPES[parts[0]["type"]][1] part_type = PARTTYPES[parts[0]["type"]][1]
self.cbox.log.info("formatting partition (%s) as '%s'" % \ self.cbox.log.info("formatting partition (%s) as '%s'" % \
(dev_name, part_type)) (dev_name, part_type))
@ -480,17 +507,26 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
return return
def __get_partition_name(self, blockdev, number): def __get_partition_device(self, blockdev, number):
"""Return the devicename of a specific partition of a device """Return the devicename of a specific partition of a device
No tests are performed, whether the partition exists or No tests are performed, whether the partition exists or
not. not.
""" """
if re.search("[0-9]$", blockdev): valid_children = []
## blockdev ends with a digit, so it is a partition, we insert a 'p' ## filter the storage devices
return "%sp%d" % (blockdev, number) for child in blockdev.children:
else: childdev = blockdevice_tools.get_blockdevice(child)
## whole disk, no 'p' necessary if childdev and childdev.is_storage():
return "%s%d" % (blockdev, number) valid_children.append(childdev)
sorted = blockdevice_tools.get_sorted_devices(valid_children)
if number <= len(sorted):
childdev = sorted[number-1]
if childdev:
return childdev.devnodes[0]
self.cbox.log.warn("Failed to get the partition name (%s, %d)" % \
(blockdev, number))
## return some guessed value - we should never get here ...
return "%s%d" % (blockdev.devnodes[0], number)
def __format_one_partition(self, dev_name, fs_type): def __format_one_partition(self, dev_name, fs_type):
@ -502,7 +538,8 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
if e.get_device() == dev_name] if e.get_device() == dev_name]
## call "mkfs" ## call "mkfs"
try: try:
cont = cryptobox.core.container.CryptoBoxContainer(dev_name, self.cbox) format_dev = blockdevice_tools.get_blockdevice(dev_name)
cont = cryptobox.core.container.CryptoBoxContainer(format_dev, self.cbox)
cont.create(cryptobox.core.container.CONTAINERTYPES["plain"], fs_type=fs_type) cont.create(cryptobox.core.container.CONTAINERTYPES["plain"], fs_type=fs_type)
except (CBInvalidType, CBCreateError, CBVolumeIsActive), err_msg: except (CBInvalidType, CBCreateError, CBVolumeIsActive), err_msg:
self.cbox.log.warn(err_msg) self.cbox.log.warn(err_msg)

View file

@ -38,7 +38,7 @@ LOGGER = logging.getLogger("CryptoBox")
DEFAULT_SYSBLOCK_DIR = '/sys/block' DEFAULT_SYSBLOCK_DIR = '/sys/block'
DEFAULT_DEVNODE_DIR = '/dev' DEFAULT_DEVNODE_DIR = '/dev'
MINIMUM_STORAGE_SIZE = 20 MINIMUM_STORAGE_SIZE = 10
MAJOR_DEVNUM_RAM = 1 MAJOR_DEVNUM_RAM = 1
MAJOR_DEVNUM_LOOP = 7 MAJOR_DEVNUM_LOOP = 7
MAJOR_DEVNUM_MD_RAID = 9 MAJOR_DEVNUM_MD_RAID = 9
@ -98,6 +98,13 @@ class Blockdevice:
sysblock_dir=DEFAULT_SYSBLOCK_DIR, sysblock_dir=DEFAULT_SYSBLOCK_DIR,
devnode_dir=DEFAULT_DEVNODE_DIR): devnode_dir=DEFAULT_DEVNODE_DIR):
"""initialize the blockdevice """initialize the blockdevice
@type dev: string
@param dev: The /sys/block/ subdirectory describing a blockdevice
@type sysblock_dir: string
@param sysblock_dir: The linux /sys/ directory. Default is '/sys'.
@type devnode_dir: string
@param devnode_dir: The linux /dev/ directory. Default is '/dev'.
""" """
self.devdir = dev self.devdir = dev
self.devnode_dir = devnode_dir self.devnode_dir = devnode_dir
@ -122,6 +129,9 @@ class Blockdevice:
usually we will have to reset the cache, too usually we will have to reset the cache, too
just in case of first-time initialization, this is not necessary just in case of first-time initialization, this is not necessary
@type empty_cache: boolean
@param empty_cache: Whether to discard the cached information or not.
""" """
CACHE.reset(["blockdevice_info", self.name]) CACHE.reset(["blockdevice_info", self.name])
self.devnum = self.__get_major_minor() self.devnum = self.__get_major_minor()
@ -141,6 +151,9 @@ class Blockdevice:
"""check if the device is usable and valid """check if the device is usable and valid
causes of invalidity: ram device, loop device, removable device causes of invalidity: ram device, loop device, removable device
@rtype: boolean
@return: 'True' for a valid blockdevice
""" """
if not self.devnodes: if not self.devnodes:
return False return False
@ -165,6 +178,9 @@ class Blockdevice:
def is_storage(self): def is_storage(self):
"""return if this device can be used as a storage """return if this device can be used as a storage
@rtype: boolean
@return: 'True' for a device usable as a storage
""" """
## check the cache first ## check the cache first
cache_link = ["blockdevice_info", self.name, "is_storage"] cache_link = ["blockdevice_info", self.name, "is_storage"]
@ -755,11 +771,24 @@ def get_blockdevice(dev,
sysblock_dir=DEFAULT_SYSBLOCK_DIR, sysblock_dir=DEFAULT_SYSBLOCK_DIR,
devnode_dir=DEFAULT_DEVNODE_DIR): devnode_dir=DEFAULT_DEVNODE_DIR):
if os.path.isabs(dev): if os.path.isabs(dev):
if os.path.isfile(os.path.join(dev, "dev")): ## it is an absolute path
devdir = dev if dev.startswith(devnode_dir):
## it is the name of a devicenode (e.g.: '/dev/hda1')
found_dev = [ a_dev for a_dev in Blockdevices(
sysblock_dir, devnode_dir).get_devices()
if dev in a_dev.devnodes ]
if found_dev:
devdir = found_dev[0].devdir
else:
return None
else: else:
return None ## it is the path of a /sys/ subdirectory (e.g.: '/sys/block/hda')
if os.path.isfile(os.path.join(dev, "dev")):
devdir = dev
else:
return None
else: else:
## the name of a blockdevice (e.g.: 'dm-0')
for one_devdir in find_blockdevices(sysblock_dir): for one_devdir in find_blockdevices(sysblock_dir):
if os.path.basename(one_devdir) == dev: if os.path.basename(one_devdir) == dev:
devdir = one_devdir devdir = one_devdir
@ -836,6 +865,25 @@ def find_lvm_pv():
return result[:] return result[:]
def get_sorted_devices(names):
"""return the names of devices in a sorted order
e.g.: "hda1", "hda5", "hda6", ..., "hda10", "hda11"
"""
# TODO: implement this for devicenames like "hda12"
def compare_device_names(x, y):
if x.name < y.name:
return -1
elif x.name == y.name:
return 0
else:
return 1
result = names[:]
result.sort(cmp=compare_device_names)
return result
def _load_preferences(): def _load_preferences():
prefs = cryptobox.core.settings.get_current_settings() prefs = cryptobox.core.settings.get_current_settings()
if not prefs is None: if not prefs is None:

View file

@ -213,6 +213,11 @@ class CryptoBox:
also check, if the device is readable and writeable for the current user also check, if the device is readable and writeable for the current user
""" """
import types import types
## if "device" is a string, then turn it into a blockdevice object
if type(device) == types.StringType:
device = blockdevice.get_blockdevice(device)
if device is None:
return False
allowed = self.prefs["Main"]["AllowedDevices"] allowed = self.prefs["Main"]["AllowedDevices"]
if type(allowed) == types.StringType: if type(allowed) == types.StringType:
allowed = [allowed] allowed = [allowed]

View file

@ -1,248 +0,0 @@
#
# Copyright 2006 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
#
"""Some useful functions for the CryptoBox.
"""
__revision__ = "$Id"
import logging
import os
import re
LOGGER = logging.getLogger("CryptoBox")
def get_available_partitions():
"retrieve a list of all available containers"
ret_list = []
try:
## the following reads all lines of /proc/partitions and adds the mentioned devices
fpart = open("/proc/partitions", "r")
try:
line = fpart.readline()
while line:
p_details = line.split()
if (len(p_details) == 4):
## the following code prevents double entries like /dev/hda and /dev/hda1
(p_major, p_minor, p_size, p_device) = p_details
## ignore lines with: invalid minor/major or extend partitions (size=1)
if re.search('^[0-9]*$', p_major) and \
re.search('^[0-9]*$', p_minor) and (p_size != "1"):
## for some parent devices we have to remove a 'p' (partition)
## an example are partitionable mdadm raid devices (e.g. md1p1)
p_parent = re.sub('p?[1-9]?[0-9]$', '', p_device)
if p_parent == p_device:
if [e for e in ret_list
if re.search('^' + p_parent + 'p?[1-9]?[0-9]$', e)]:
## major partition - its children are already in the list
pass
else:
## major partition - but there are no children for now
ret_list.append(p_device)
else:
## minor partition - remove parent if necessary
if p_parent in ret_list:
ret_list.remove(p_parent)
ret_list.append(p_device)
line = fpart.readline()
finally:
fpart.close()
return [ get_absolute_devicename(e) for e in ret_list ]
except IOError:
LOGGER.warning("Could not read /proc/partitions")
return []
def get_absolute_devicename(shortname):
""" returns the absolute file name of a device (e.g.: "hda1" -> "/dev/hda1")
this does also work for device mapper devices
if the result is non-unique, one arbitrary value is returned
"""
if re.search('^/', shortname):
return shortname
default = os.path.join("/dev", shortname)
if os.path.exists(default):
return default
result = find_major_minor_of_device(shortname)
## if no valid major/minor was found -> exit
if not result:
return default
(major, minor) = result
## for device-mapper devices (major == 254) ...
if major == 254:
result = find_major_minor_device("/dev/mapper", major, minor)
if result:
return result[0]
## now check all files in /dev
result = find_major_minor_device("/dev", major, minor)
if result:
return result[0]
return default
def find_major_minor_of_device(device):
"""Return the major/minor numbers of a block device.
"""
if re.match("/", device) or \
not os.path.exists(os.path.join(os.path.sep, "sys", "block", device)):
## maybe it is an absolute device name
if not os.path.exists(device):
return None
## okay - it seems to to a device node
rdev = os.stat(device).st_rdev
return (os.major(rdev), os.minor(rdev))
blockdev_info_file = os.path.join(os.path.join(
os.path.sep,"sys","block", device), "dev")
try:
f_blockdev_info = open(blockdev_info_file, "r")
blockdev_info = f_blockdev_info.read()
f_blockdev_info.close()
(str_major, str_minor) = blockdev_info.split(":")
## numeric conversion
try:
major = int(str_major)
minor = int(str_minor)
return (major, minor)
except ValueError:
## unknown device numbers -> stop guessing
return None
except IOError:
pass
return None
def find_major_minor_device(dirpath, major, minor):
"""Returns the names of devices with the specified major and minor number.
"""
collected = []
try:
subdirs = [os.path.join(dirpath, e) for e in os.listdir(dirpath)
if (not os.path.islink(os.path.join(dirpath, e))) and \
os.path.isdir(os.path.join(dirpath, e))]
## do a recursive call to parse the directory tree
for dirs in subdirs:
collected.extend(find_major_minor_device(dirs, major, minor))
## filter all device inodes in this directory
collected.extend([os.path.realpath(os.path.join(dirpath, e))
for e in os.listdir(dirpath)
if (os.major(os.stat(os.path.join(dirpath, e)).st_rdev) == major) \
and (os.minor(os.stat(os.path.join(dirpath, e)).st_rdev) == minor)])
## remove double entries
result = []
for item in collected:
if item not in result:
result.append(item)
return result
except OSError:
return []
def get_parent_blockdevices():
"""Return a list of all block devices that contain other devices.
"""
devs = []
for line in file("/proc/partitions"):
p_details = line.split()
## we expect four values - otherwise continue with next iteration
if len(p_details) != 4:
continue
(p_major, p_minor, p_size, p_device) = p_details
## we expect numeric values in the first two columns
if re.search(r'\D', p_major) or re.search(r'\D', p_minor):
continue
## now let us check, if it is a (parent) block device or a partition
if not os.path.isdir(os.path.join(os.path.sep, "sys", "block", p_device)):
continue
devs.append(p_device)
return [ get_absolute_devicename(e) for e in devs ]
def is_part_of_blockdevice(parent, subdevice):
"""Check if the given block device is a parent of 'subdevice'.
e.g. for checking if a partition belongs to a block device
"""
try:
(par_major, par_minor) = find_major_minor_of_device(parent)
(sub_major, sub_minor) = find_major_minor_of_device(subdevice)
except TypeError:
## at least one of these devices did not return a valid major/minor combination
return False
## search the entry below '/sys/block' belonging to the parent
root = os.path.join(os.path.sep, 'sys', 'block')
for bldev in os.listdir(root):
blpath = os.path.join(root, bldev, 'dev')
if os.access(blpath, os.R_OK):
try:
if (str(par_major), str(par_minor)) == tuple([e
for e in file(blpath)][0].strip().split(":",1)):
parent_path = os.path.join(root, bldev)
break
except (IndexError, OSError):
pass
else:
## no block device with this major/minor combination found below '/sys/block'
return False
for subbldev in os.listdir(parent_path):
subblpath = os.path.join(parent_path, subbldev, "dev")
if os.access(subblpath, os.R_OK):
try:
if (str(sub_major), str(sub_minor)) == tuple([e
for e in file(subblpath)][0].strip().split(":",1)):
## the name of the subdevice node is not important - we found it!
return True
except (IndexError, OSError):
pass
return False
def get_blockdevice_size(device):
"""Return the size of a blockdevice in megabyte.
"""
if not device:
return -1
try:
rdev = os.stat(device).st_rdev
except OSError:
return -1
minor = os.minor(rdev)
major = os.major(rdev)
for line in file("/proc/partitions"):
try:
elements = line.split()
if len(elements) != 4:
continue
if (int(elements[0]) == major) and (int(elements[1]) == minor):
return int(elements[2])/1024
except ValueError:
pass
return -1
def get_blockdevice_size_humanly(device):
"""Return a human readable size of a blockdevice.
"""
size = get_blockdevice_size(device)
if size > 5120:
return "%dGB" % int(size/1024)
else:
return "%dMB" % size

View file

@ -324,7 +324,7 @@ class WebInterfaceSites:
## it will get ignored for non-volume plugins ## it will get ignored for non-volume plugins
plugin.device = None plugin.device = None
if device and self.__set_device(device): if device and self.__set_device(device):
plugin.device = self.cbox.get_container(device).device plugin.device = self.cbox.get_container(device)
## check the device argument of volume plugins ## check the device argument of volume plugins
if "volume" in plugin.plugin_capabilities: if "volume" in plugin.plugin_capabilities:
## initialize the dataset of the selected device if necessary ## initialize the dataset of the selected device if necessary