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:
parent
4a4778d876
commit
9c649312d0
5 changed files with 143 additions and 301 deletions
|
@ -27,7 +27,7 @@ import subprocess
|
|||
import os
|
||||
import re
|
||||
import logging
|
||||
import cryptobox.core.tools as cbox_tools
|
||||
import cryptobox.core.blockdevice as blockdevice_tools
|
||||
import cryptobox.plugins.base
|
||||
from cryptobox.core.exceptions import *
|
||||
|
||||
|
@ -58,15 +58,19 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
self.__prepare_dataset()
|
||||
## retrieve some values from 'args' - defaults are empty
|
||||
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(
|
||||
"partition plugin: selected device=%s" % str(self.blockdevice))
|
||||
self.blockdevice_size = self.__get_available_device_size(self.blockdevice)
|
||||
## no (or invalid) device was supplied
|
||||
if not self.blockdevice:
|
||||
return self.__action_select_device()
|
||||
## 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"
|
||||
return self.__action_select_device()
|
||||
## no confirm setting?
|
||||
|
@ -91,15 +95,19 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
"partition: invalid partition number to delete (%s)" % del_args[0])
|
||||
return self.__action_select_device()
|
||||
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()
|
||||
|
||||
|
||||
def get_status(self):
|
||||
"""The status of this plugin is the selected device and some information.
|
||||
"""
|
||||
return "%s / %s / %s" % (self.blockdevice, self.blockdevice_size,
|
||||
self.with_config_partition)
|
||||
if not self.blockdevice:
|
||||
return "no blockdevice selected"
|
||||
else:
|
||||
return "%s / %s / %s" % (self.blockdevice.name,
|
||||
self.blockdevice_size, self.with_config_partition)
|
||||
|
||||
|
||||
def get_warnings(self):
|
||||
|
@ -131,7 +139,13 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
"""Check the selected device (valid, not busy, ...).
|
||||
"""
|
||||
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:
|
||||
return None
|
||||
if not self.__is_device_valid(blockdevice):
|
||||
|
@ -149,8 +163,6 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
return False
|
||||
if not self.cbox.is_device_allowed(blockdevice):
|
||||
return False
|
||||
if not blockdevice in cbox_tools.get_parent_blockdevices():
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
|
@ -158,9 +170,10 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
"""check if the device (or one of its partitions) is mounted
|
||||
"""
|
||||
## the config partition is ignored, as it will get unmounted if necessary
|
||||
for cont in self.cbox.get_container_list():
|
||||
if cbox_tools.is_part_of_blockdevice(blockdevice, cont.get_device()) \
|
||||
and cont.is_mounted():
|
||||
for dev in blockdevice.children:
|
||||
container = self.cbox.get_container(
|
||||
blockdevice_tools.get_blockdevice(dev).devnodes[0])
|
||||
if container and (container.is_mounted() or container.is_busy()):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -168,15 +181,17 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
def __action_select_device(self):
|
||||
"""Show a form to select the device for partitioning.
|
||||
"""
|
||||
block_devices = [e
|
||||
for e in cbox_tools.get_parent_blockdevices()
|
||||
if self.cbox.is_device_allowed(e)]
|
||||
block_devices = [ e for e in
|
||||
blockdevice_tools.Blockdevices().get_partitionable_devices()
|
||||
if self.cbox.is_device_allowed(e) ]
|
||||
counter = 0
|
||||
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] = \
|
||||
cbox_tools.get_blockdevice_size_humanly(dev)
|
||||
self.cbox.log.debug("found a suitable block device: %s" % dev)
|
||||
dev.size_human
|
||||
self.cbox.log.debug("found a suitable block device: %s" % \
|
||||
dev.devnodes[0])
|
||||
counter += 1
|
||||
if self.with_config_partition:
|
||||
self.hdf[self.hdf_prefix + "CreateConfigPartition"] = "1"
|
||||
|
@ -189,7 +204,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
def __action_add_partition(self, args):
|
||||
"""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
|
||||
parts = self.__get_partitions_from_args(args)
|
||||
self.__set_partition_data(parts)
|
||||
|
@ -199,7 +214,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
def __action_del_partition(self, args, part_num):
|
||||
"""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
|
||||
parts = self.__get_partitions_from_args(args)
|
||||
## valid partition number to be deleted?
|
||||
|
@ -215,8 +230,11 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
parts = self.__get_partitions_from_args(args)
|
||||
if parts:
|
||||
self.__set_partition_data(parts)
|
||||
if cbox_tools.is_part_of_blockdevice(self.blockdevice,
|
||||
self.cbox.prefs.get_active_partition()):
|
||||
## umount config partition if necessary
|
||||
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()
|
||||
if not self.__run_fdisk(parts):
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
|
||||
|
@ -257,9 +275,10 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
format_ok = False
|
||||
if format_ok:
|
||||
self.hdf["Data.Success"] = "Plugins.partition.Partitioned"
|
||||
return { "plugin":"system_preferences", "values":[] }
|
||||
else:
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.FormattingFailed"
|
||||
return "empty"
|
||||
return "empty"
|
||||
else:
|
||||
return self.__action_add_partition(args)
|
||||
|
||||
|
@ -270,15 +289,17 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
import types
|
||||
## we do not have to take special care for a possible config partition
|
||||
parts = [ { "size": self.blockdevice_size, "type": "windows" } ]
|
||||
## umount partition if necessary
|
||||
if cbox_tools.is_part_of_blockdevice(self.blockdevice,
|
||||
self.cbox.prefs.get_active_partition()):
|
||||
## umount config partition if necessary
|
||||
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()
|
||||
## partition it
|
||||
if not self.__run_fdisk(parts):
|
||||
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
|
||||
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)
|
||||
if type(e) == types.BooleanType]
|
||||
if self.with_config_partition:
|
||||
|
@ -317,11 +338,12 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
for ptype in PARTTYPES.keys():
|
||||
self.hdf[self.hdf_prefix + "Types.%s" % ptype] = ptype
|
||||
## store the currently existing partitions of the choosen block device
|
||||
current_containers = [ e for e in self.cbox.get_container_list()
|
||||
if cbox_tools.is_part_of_blockdevice(self.blockdevice, e.get_device()) ]
|
||||
current_containers = [ blockdevice_tools.get_blockdevice(dev)
|
||||
for dev in self.blockdevice.children
|
||||
if blockdevice_tools.get_blockdevice(dev).is_storage() ]
|
||||
for (index, cont) in enumerate(current_containers):
|
||||
self.hdf[self.hdf_prefix + "ExistingContainers.%d" % index] = \
|
||||
cont.get_device()
|
||||
cont.name
|
||||
|
||||
|
||||
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
|
||||
also consider a (possible) configuration partition
|
||||
"""
|
||||
device_size = cbox_tools.get_blockdevice_size(device)
|
||||
if device_size < 0:
|
||||
return 0
|
||||
device_size = device.size
|
||||
if self.with_config_partition:
|
||||
device_size -= CONFIGPARTITION["size"]
|
||||
if device_size < 0:
|
||||
return 0
|
||||
return device_size
|
||||
|
||||
|
||||
|
@ -378,7 +400,12 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
if not active:
|
||||
return True
|
||||
## 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
|
||||
|
||||
|
||||
|
@ -402,7 +429,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
"plugin",
|
||||
os.path.join(self.plugin_dir, "root_action.py"),
|
||||
"partition",
|
||||
self.blockdevice])
|
||||
self.blockdevice.devnodes[0]])
|
||||
for line in self.__get_sfdisk_layout(parts, is_filled):
|
||||
proc.stdin.write(line + "\n")
|
||||
#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
|
||||
## maybe a 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)
|
||||
if self.__format_one_partition(dev_name, CONFIGPARTITION["fs"]):
|
||||
self.__set_label_of_partition(dev_name,
|
||||
self.cbox.prefs["Main"]["ConfigVolumeLabel"])
|
||||
part_num += 1
|
||||
## 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]
|
||||
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, part_type))
|
||||
yield self.__format_one_partition(dev_name, part_type)
|
||||
del parts[0]
|
||||
## other data partitions
|
||||
part_num = 5
|
||||
part_num += 1
|
||||
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]
|
||||
self.cbox.log.info("formatting partition (%s) as '%s'" % \
|
||||
(dev_name, part_type))
|
||||
|
@ -480,17 +507,26 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
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
|
||||
No tests are performed, whether the partition exists or
|
||||
not.
|
||||
"""
|
||||
if re.search("[0-9]$", blockdev):
|
||||
## blockdev ends with a digit, so it is a partition, we insert a 'p'
|
||||
return "%sp%d" % (blockdev, number)
|
||||
else:
|
||||
## whole disk, no 'p' necessary
|
||||
return "%s%d" % (blockdev, number)
|
||||
valid_children = []
|
||||
## filter the storage devices
|
||||
for child in blockdev.children:
|
||||
childdev = blockdevice_tools.get_blockdevice(child)
|
||||
if childdev and childdev.is_storage():
|
||||
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):
|
||||
|
@ -502,7 +538,8 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
|||
if e.get_device() == dev_name]
|
||||
## call "mkfs"
|
||||
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)
|
||||
except (CBInvalidType, CBCreateError, CBVolumeIsActive), err_msg:
|
||||
self.cbox.log.warn(err_msg)
|
||||
|
|
|
@ -38,7 +38,7 @@ LOGGER = logging.getLogger("CryptoBox")
|
|||
|
||||
DEFAULT_SYSBLOCK_DIR = '/sys/block'
|
||||
DEFAULT_DEVNODE_DIR = '/dev'
|
||||
MINIMUM_STORAGE_SIZE = 20
|
||||
MINIMUM_STORAGE_SIZE = 10
|
||||
MAJOR_DEVNUM_RAM = 1
|
||||
MAJOR_DEVNUM_LOOP = 7
|
||||
MAJOR_DEVNUM_MD_RAID = 9
|
||||
|
@ -98,6 +98,13 @@ class Blockdevice:
|
|||
sysblock_dir=DEFAULT_SYSBLOCK_DIR,
|
||||
devnode_dir=DEFAULT_DEVNODE_DIR):
|
||||
"""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.devnode_dir = devnode_dir
|
||||
|
@ -122,6 +129,9 @@ class Blockdevice:
|
|||
|
||||
usually we will have to reset the cache, too
|
||||
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])
|
||||
self.devnum = self.__get_major_minor()
|
||||
|
@ -141,6 +151,9 @@ class Blockdevice:
|
|||
"""check if the device is usable and valid
|
||||
|
||||
causes of invalidity: ram device, loop device, removable device
|
||||
|
||||
@rtype: boolean
|
||||
@return: 'True' for a valid blockdevice
|
||||
"""
|
||||
if not self.devnodes:
|
||||
return False
|
||||
|
@ -165,6 +178,9 @@ class Blockdevice:
|
|||
|
||||
def is_storage(self):
|
||||
"""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
|
||||
cache_link = ["blockdevice_info", self.name, "is_storage"]
|
||||
|
@ -755,11 +771,24 @@ def get_blockdevice(dev,
|
|||
sysblock_dir=DEFAULT_SYSBLOCK_DIR,
|
||||
devnode_dir=DEFAULT_DEVNODE_DIR):
|
||||
if os.path.isabs(dev):
|
||||
if os.path.isfile(os.path.join(dev, "dev")):
|
||||
devdir = dev
|
||||
## it is an absolute path
|
||||
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:
|
||||
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:
|
||||
## the name of a blockdevice (e.g.: 'dm-0')
|
||||
for one_devdir in find_blockdevices(sysblock_dir):
|
||||
if os.path.basename(one_devdir) == dev:
|
||||
devdir = one_devdir
|
||||
|
@ -836,6 +865,25 @@ def find_lvm_pv():
|
|||
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():
|
||||
prefs = cryptobox.core.settings.get_current_settings()
|
||||
if not prefs is None:
|
||||
|
|
|
@ -213,6 +213,11 @@ class CryptoBox:
|
|||
also check, if the device is readable and writeable for the current user
|
||||
"""
|
||||
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"]
|
||||
if type(allowed) == types.StringType:
|
||||
allowed = [allowed]
|
||||
|
|
|
@ -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
|
||||
|
|
@ -324,7 +324,7 @@ class WebInterfaceSites:
|
|||
## it will get ignored for non-volume plugins
|
||||
plugin.device = None
|
||||
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
|
||||
if "volume" in plugin.plugin_capabilities:
|
||||
## initialize the dataset of the selected device if necessary
|
||||
|
|
Loading…
Reference in a new issue