improved implementation of blockdevice cache
added UUID detection for blockdevices changed interface of cryptobox.core.container and cryptobox.core.main for new blockdevice detection * beware: the change is not finished - the cryptobox is not working properly for now
This commit is contained in:
parent
b72310097c
commit
35a6570a52
|
@ -3,5 +3,5 @@
|
||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
__all__ = [ 'main', 'container', 'exceptions', 'tools', 'settings' ]
|
__all__ = [ 'main', 'container', 'exceptions', 'blockdevice', 'settings' ]
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,13 @@ These classes detect and filter available blockdevices.
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
|
||||||
#TODO: use logger to report interesting behaviour
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
import logging
|
||||||
import cryptobox.core.settings
|
import cryptobox.core.settings
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger("CryptoBox")
|
||||||
|
|
||||||
DEFAULT_SYSBLOCK_DIR = '/sys/block'
|
DEFAULT_SYSBLOCK_DIR = '/sys/block'
|
||||||
DEFAULT_DEVNODE_DIR = '/dev'
|
DEFAULT_DEVNODE_DIR = '/dev'
|
||||||
|
@ -40,14 +40,18 @@ MAJOR_DEVNUM_RAM = 1
|
||||||
MAJOR_DEVNUM_LOOP = 7
|
MAJOR_DEVNUM_LOOP = 7
|
||||||
MAJOR_DEVNUM_MD_RAID = 9
|
MAJOR_DEVNUM_MD_RAID = 9
|
||||||
|
|
||||||
USE_CACHE = True
|
## cache settings
|
||||||
|
CACHE_ENABLED = True
|
||||||
CACHE_EXPIRE_SECONDS = 60
|
CACHE_EXPIRE_SECONDS = 60
|
||||||
|
CACHE_MONITOR_FILE = '/proc/partitions'
|
||||||
|
|
||||||
#TODO: remove this after profiling
|
## useful for manual profiling
|
||||||
IS_VISIBLE = True
|
IS_VISIBLE = True
|
||||||
|
|
||||||
## caching is quite important for the following implementation
|
## caching is quite important for the following implementation
|
||||||
CACHED_VALUES = {}
|
## the object will be initializes later below
|
||||||
|
CACHE = None
|
||||||
|
|
||||||
|
|
||||||
class Blockdevices:
|
class Blockdevices:
|
||||||
"""handle all blockdevices of this system
|
"""handle all blockdevices of this system
|
||||||
|
@ -72,6 +76,18 @@ class Blockdevices:
|
||||||
return self.devices[:]
|
return self.devices[:]
|
||||||
|
|
||||||
|
|
||||||
|
def get_storage_devices(self):
|
||||||
|
"""return a list of devices with the 'storage' flag
|
||||||
|
"""
|
||||||
|
return [ dev for dev in self.devices if dev.is_storage() ]
|
||||||
|
|
||||||
|
|
||||||
|
def get_partitionable_devices(self):
|
||||||
|
"""return a list of devices with the 'partitionable' flag
|
||||||
|
"""
|
||||||
|
return [ dev for dev in self.devices if dev.is_partitionable() ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Blockdevice:
|
class Blockdevice:
|
||||||
|
|
||||||
|
@ -84,17 +100,40 @@ class Blockdevice:
|
||||||
self.devnode_dir = devnode_dir
|
self.devnode_dir = devnode_dir
|
||||||
self.sysblock_dir = sysblock_dir
|
self.sysblock_dir = sysblock_dir
|
||||||
self.name = os.path.basename(self.devdir)
|
self.name = os.path.basename(self.devdir)
|
||||||
|
## "reset" below will fill these values
|
||||||
|
self.devnum = None
|
||||||
|
self.size = None
|
||||||
|
self.size_human = None
|
||||||
|
self.range = None
|
||||||
|
self.slaves = None
|
||||||
|
self.holders = None
|
||||||
|
self.children = None
|
||||||
|
self.devnodes = None
|
||||||
|
self.uuid = None
|
||||||
|
self.label = None
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""reread the data of the device
|
||||||
|
"""
|
||||||
|
CACHE.reset(["blockdevice_info", self.name])
|
||||||
self.devnum = self.__get_major_minor()
|
self.devnum = self.__get_major_minor()
|
||||||
self.size = self.__get_size()
|
self.size = self.__get_size()
|
||||||
|
self.size_human = self.__get_size_human()
|
||||||
self.range = self.__get_device_range()
|
self.range = self.__get_device_range()
|
||||||
self.slaves = self.__get_dev_related("slaves")
|
self.slaves = self.__get_dev_related("slaves")
|
||||||
self.holders = self.__get_dev_related("holders")
|
self.holders = self.__get_dev_related("holders")
|
||||||
self.children = self.__get_children()
|
self.children = self.__get_children()
|
||||||
self.devnodes = self.__get_device_nodes()
|
self.devnodes = self.__get_device_nodes()
|
||||||
|
self.uuid = self.__get_uuid()
|
||||||
|
self.label = self.__get_label()
|
||||||
|
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
"""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
|
||||||
"""
|
"""
|
||||||
if not self.devnodes:
|
if not self.devnodes:
|
||||||
return False
|
return False
|
||||||
|
@ -109,6 +148,9 @@ class Blockdevice:
|
||||||
## loop devices are ignored
|
## loop devices are ignored
|
||||||
if major == MAJOR_DEVNUM_LOOP:
|
if major == MAJOR_DEVNUM_LOOP:
|
||||||
return False
|
return False
|
||||||
|
## removable devices are ignored (due to long timeouts)
|
||||||
|
if self.is_removable():
|
||||||
|
return False
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
@ -119,38 +161,38 @@ class Blockdevice:
|
||||||
"""
|
"""
|
||||||
## check the cache first
|
## check the cache first
|
||||||
cache_link = ["blockdevice_info", self.name, "is_storage"]
|
cache_link = ["blockdevice_info", self.name, "is_storage"]
|
||||||
cached = _get_cached_value(cache_link)
|
cached = CACHE.get(cache_link)
|
||||||
if not cached is None:
|
if not cached is None:
|
||||||
return cached
|
return cached
|
||||||
|
|
||||||
if self.range > 1:
|
if self.range > 1:
|
||||||
## partitionable blockdevice
|
## partitionable blockdevice
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
if self.size < MINIMUM_STORAGE_SIZE:
|
if self.size < MINIMUM_STORAGE_SIZE:
|
||||||
## extended partition, unused loop device
|
## extended partition, unused loop device
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
if self.devnum[0] == MAJOR_DEVNUM_RAM:
|
if self.devnum[0] == MAJOR_DEVNUM_RAM:
|
||||||
## ram device
|
## ram device
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
## are we the device mapper of a luks device?
|
## are we the device mapper of a luks device?
|
||||||
for slave in self.slaves:
|
for slave in self.slaves:
|
||||||
if get_blockdevice(slave, self.sysblock_dir,
|
if get_blockdevice(slave, self.sysblock_dir,
|
||||||
self.devnode_dir).is_luks():
|
self.devnode_dir).is_luks():
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
## if we are a luks device with exactly one child, then
|
## if we are a luks device with exactly one child, then
|
||||||
## we are a storage
|
## we are a storage
|
||||||
if (len(self.children) == 1) and self.is_luks():
|
if (len(self.children) == 1) and self.is_luks():
|
||||||
_set_cached_value(cache_link, True)
|
CACHE.set(cache_link, True)
|
||||||
return True
|
return True
|
||||||
if self.children:
|
if self.children:
|
||||||
## a parent blockdevice
|
## a parent blockdevice
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
_set_cached_value(cache_link, True)
|
CACHE.set(cache_link, True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,16 +210,16 @@ class Blockdevice:
|
||||||
"""
|
"""
|
||||||
## check the cache first
|
## check the cache first
|
||||||
cache_link = ["blockdevice_info", self.name, "is_lvm_pv"]
|
cache_link = ["blockdevice_info", self.name, "is_lvm_pv"]
|
||||||
cached = _get_cached_value(cache_link)
|
cached = CACHE.get(cache_link)
|
||||||
if not cached is None:
|
if not cached is None:
|
||||||
return cached
|
return cached
|
||||||
|
|
||||||
## is one of the devnodes of the device a physical volume?
|
## is one of the devnodes of the device a physical volume?
|
||||||
for one_lvm_pv in find_lvm_pv():
|
for one_lvm_pv in find_lvm_pv():
|
||||||
if one_lvm_pv in self.devnodes:
|
if one_lvm_pv in self.devnodes:
|
||||||
_set_cached_value(cache_link, True)
|
CACHE.set(cache_link, True)
|
||||||
return True
|
return True
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,23 +228,23 @@ class Blockdevice:
|
||||||
"""
|
"""
|
||||||
## check the cache first
|
## check the cache first
|
||||||
cache_link = ["blockdevice_info", self.name, "is_lvm_lv"]
|
cache_link = ["blockdevice_info", self.name, "is_lvm_lv"]
|
||||||
cached = _get_cached_value(cache_link)
|
cached = CACHE.get(cache_link)
|
||||||
if not cached is None:
|
if not cached is None:
|
||||||
return cached
|
return cached
|
||||||
|
|
||||||
## is one of the devnodes of the device a physical volume?
|
## is one of the devnodes of the device a physical volume?
|
||||||
## logical LVM volumes always depend on their physical volumes
|
## logical LVM volumes always depend on their physical volumes
|
||||||
if not self.slaves:
|
if not self.slaves:
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
## is one of the LVM physical volumes a device node of our slave(s)?
|
## is one of the LVM physical volumes a device node of our slave(s)?
|
||||||
for one_lvm_pv in find_lvm_pv():
|
for one_lvm_pv in find_lvm_pv():
|
||||||
for one_slave in self.slaves:
|
for one_slave in self.slaves:
|
||||||
if one_lvm_pv in get_blockdevice(one_slave,
|
if one_lvm_pv in get_blockdevice(one_slave,
|
||||||
self.sysblock_dir, self.devnode_dir).devnodes:
|
self.sysblock_dir, self.devnode_dir).devnodes:
|
||||||
_set_cached_value(cache_link, True)
|
CACHE.set(cache_link, True)
|
||||||
return True
|
return True
|
||||||
_set_cached_value(cache_link, False)
|
CACHE.set(cache_link, False)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,7 +253,7 @@ class Blockdevice:
|
||||||
"""
|
"""
|
||||||
## check the cache first
|
## check the cache first
|
||||||
cache_link = ["blockdevice_info", self.name, "is_md_raid"]
|
cache_link = ["blockdevice_info", self.name, "is_md_raid"]
|
||||||
cached = _get_cached_value(cache_link)
|
cached = CACHE.get(cache_link)
|
||||||
if not cached is None:
|
if not cached is None:
|
||||||
return cached
|
return cached
|
||||||
|
|
||||||
|
@ -229,7 +271,7 @@ class Blockdevice:
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
## store result and return
|
## store result and return
|
||||||
_set_cached_value(cache_link, result)
|
CACHE.set(cache_link, result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,7 +280,7 @@ class Blockdevice:
|
||||||
"""
|
"""
|
||||||
## check the cache first
|
## check the cache first
|
||||||
cache_link = ["blockdevice_info", self.name, "is_luks"]
|
cache_link = ["blockdevice_info", self.name, "is_luks"]
|
||||||
cached = _get_cached_value(cache_link)
|
cached = CACHE.get(cache_link)
|
||||||
if not cached is None:
|
if not cached is None:
|
||||||
return cached
|
return cached
|
||||||
|
|
||||||
|
@ -262,7 +304,33 @@ class Blockdevice:
|
||||||
proc.wait()
|
proc.wait()
|
||||||
result = proc.returncode == 0
|
result = proc.returncode == 0
|
||||||
## store result and return
|
## store result and return
|
||||||
_set_cached_value(cache_link, result)
|
CACHE.set(cache_link, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def is_removable(self):
|
||||||
|
"""check if the device is marked as 'removable'
|
||||||
|
"""
|
||||||
|
## check the cache first
|
||||||
|
cache_link = ["blockdevice_info", self.name, "is_removable"]
|
||||||
|
cached = CACHE.get(cache_link)
|
||||||
|
if not cached is None:
|
||||||
|
return cached
|
||||||
|
|
||||||
|
removable_file = os.path.join(self.devdir, "removable")
|
||||||
|
if os.path.isfile(removable_file):
|
||||||
|
try:
|
||||||
|
content = file(removable_file).read().strip()
|
||||||
|
if content == "1":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except IOError:
|
||||||
|
result = False
|
||||||
|
else:
|
||||||
|
result = False
|
||||||
|
|
||||||
|
CACHE.set(cache_link, result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,12 +343,23 @@ class Blockdevice:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def __get_size_human(self):
|
||||||
|
"""return a human readable string representing the size of the device
|
||||||
|
"""
|
||||||
|
size = self.size
|
||||||
|
if self.size > 5120:
|
||||||
|
return "%dGB" % int(self.size/1024)
|
||||||
|
else:
|
||||||
|
return "%dMB" % self.size
|
||||||
|
|
||||||
|
|
||||||
def __get_size(self):
|
def __get_size(self):
|
||||||
"""return the size (in kB) of the blockdevice
|
"""return the size (in MB) of the blockdevice
|
||||||
"""
|
"""
|
||||||
default = 0
|
default = 0
|
||||||
try:
|
try:
|
||||||
return int(file(os.path.join(self.devdir, 'size')).read())
|
size_kb = int(file(os.path.join(self.devdir, 'size')).read())
|
||||||
|
return int(size_kb/1024)
|
||||||
except OSError:
|
except OSError:
|
||||||
return default
|
return default
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -358,6 +437,150 @@ class Blockdevice:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def __get_uuid(self):
|
||||||
|
"""determine the unique identifier of this device
|
||||||
|
|
||||||
|
returns None in case of error or for invalid devices (see "is_valid")
|
||||||
|
"""
|
||||||
|
if not self.is_valid():
|
||||||
|
return None
|
||||||
|
## partitionable devices do not have a UUID
|
||||||
|
if self.is_partitionable():
|
||||||
|
return None
|
||||||
|
## UUIDs of physical LVM volumes can only be determined via pvdisplay
|
||||||
|
if self.is_lvm_pv():
|
||||||
|
return self.__get_uuid_lvm_pv()
|
||||||
|
## UUIDs of luks devices can be determined via luksDump
|
||||||
|
if self.is_luks():
|
||||||
|
return self.__get_uuid_luks()
|
||||||
|
return self.__get_uuid_default()
|
||||||
|
|
||||||
|
|
||||||
|
def __get_uuid_luks(self):
|
||||||
|
"""determine the unique identifier of luks devices
|
||||||
|
"""
|
||||||
|
prefs = _load_preferences()
|
||||||
|
try:
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
shell = False,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE,
|
||||||
|
args = [ prefs["Programs"]["cryptsetup"],
|
||||||
|
"luksUUID", self.devnodes[0] ])
|
||||||
|
proc.wait()
|
||||||
|
except OSError, err_msg:
|
||||||
|
LOGGER.warning("Failed to call '%s' to determine UUID: %s" \
|
||||||
|
% (prefs["Programs"]["cryptsetup"], err_msg))
|
||||||
|
return None
|
||||||
|
if proc.returncode != 0:
|
||||||
|
LOGGER.warning("Execution of '%s' failed: %s" % \
|
||||||
|
(prefs["Programs"]["cryptsetup"],
|
||||||
|
proc.stderr.read().strip()))
|
||||||
|
return None
|
||||||
|
result = proc.stdout.read().strip()
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def __get_uuid_lvm_pv(self):
|
||||||
|
"""determine the unique identifier of physical LVM volumes
|
||||||
|
"""
|
||||||
|
prefs = _load_preferences()
|
||||||
|
try:
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
shell = False,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE,
|
||||||
|
args = [ prefs["Programs"]["super"],
|
||||||
|
prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
|
"program", "pvdisplay" ])
|
||||||
|
proc.wait()
|
||||||
|
except OSError, err_msg:
|
||||||
|
LOGGER.warning("Failed to call '%s' via 'super' to determine " \
|
||||||
|
% prefs["Programs"]["pvdisplay"] + "UUID: %s" % err_msg)
|
||||||
|
return None
|
||||||
|
if proc.returncode != 0:
|
||||||
|
LOGGER.warning("Execution of 'pvdisplay' failed: %s" % \
|
||||||
|
proc.stderr.read().strip())
|
||||||
|
return None
|
||||||
|
for line in proc.stdout.readlines():
|
||||||
|
items = line.strip().split(":")
|
||||||
|
if (len(items) == 12) and (items[0] in self.devnodes):
|
||||||
|
return items[11]
|
||||||
|
## not found
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def __get_uuid_default(self):
|
||||||
|
"""determine the unique identifier for non-special devices
|
||||||
|
|
||||||
|
luks and lvm_pv devices must be treated differently
|
||||||
|
"""
|
||||||
|
prefs = _load_preferences()
|
||||||
|
try:
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
shell = False,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE,
|
||||||
|
args = [ prefs["Programs"]["blkid"],
|
||||||
|
"-s", "UUID",
|
||||||
|
"-o", "value",
|
||||||
|
"-c", os.devnull,
|
||||||
|
"-w", os.devnull,
|
||||||
|
self.devnodes[0] ])
|
||||||
|
proc.wait()
|
||||||
|
except OSError, err_msg:
|
||||||
|
LOGGER.warning("Failed to call '%s' to determine UUID: %s" % \
|
||||||
|
(prefs["Programs"]["blkid"], err_msg))
|
||||||
|
return None
|
||||||
|
if proc.returncode != 0:
|
||||||
|
LOGGER.warning("Execution of '%s' failed: %s" % \
|
||||||
|
(prefs["Programs"]["blkid"], proc.stderr.read().strip()))
|
||||||
|
return None
|
||||||
|
result = proc.stdout.read().strip()
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def __get_label(self):
|
||||||
|
"""determine the label of a filesystem contained in a device
|
||||||
|
|
||||||
|
return None for errors, empty labels and for non-storage devices
|
||||||
|
"""
|
||||||
|
if not self.is_valid():
|
||||||
|
return None
|
||||||
|
prefs = _load_preferences()
|
||||||
|
try:
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
shell = False,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE,
|
||||||
|
args = [ prefs["Programs"]["blkid"],
|
||||||
|
"-s", "LABEL",
|
||||||
|
"-o", "value",
|
||||||
|
"-c", os.devnull,
|
||||||
|
"-w", os.devnull,
|
||||||
|
self.devnodes[0]])
|
||||||
|
proc.wait()
|
||||||
|
except OSError, err_msg:
|
||||||
|
LOGGER.warning("Failed to call '%s' to determine label: %s" % \
|
||||||
|
(prefs["Programs"]["blkid"], err_msg))
|
||||||
|
return None
|
||||||
|
if proc.returncode != 0:
|
||||||
|
LOGGER.warning("Execution of '%s' failed: %s" % \
|
||||||
|
(prefs["Programs"]["blkid"], proc.stderr.read().strip()))
|
||||||
|
return None
|
||||||
|
result = proc.stdout.read().strip()
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""display the name of the device
|
"""display the name of the device
|
||||||
"""
|
"""
|
||||||
|
@ -370,6 +593,8 @@ class Blockdevice:
|
||||||
output = "%s:\n" % self.name
|
output = "%s:\n" % self.name
|
||||||
output += "\t%s:\t%s\n" % ("blockdir", self.devdir)
|
output += "\t%s:\t%s\n" % ("blockdir", self.devdir)
|
||||||
output += "\t%s:\t%s\n" % ("major/minor", self.devnum)
|
output += "\t%s:\t%s\n" % ("major/minor", self.devnum)
|
||||||
|
output += "\t%s:\t\t%s\n" % ("label", self.label)
|
||||||
|
output += "\t%s:\t\t%s\n" % ("UUID", self.uuid)
|
||||||
output += "\t%s:\t\t%s\n" % ("range", self.range)
|
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" % ("size", self.size)
|
||||||
output += "\t%s:\t\t%s\n" % ("slaves", self.slaves)
|
output += "\t%s:\t\t%s\n" % ("slaves", self.slaves)
|
||||||
|
@ -377,14 +602,98 @@ class Blockdevice:
|
||||||
output += "\t%s:\t%s\n" % ("children", self.children)
|
output += "\t%s:\t%s\n" % ("children", self.children)
|
||||||
output += "\t%s:\t%s\n" % ("device nodes", self.devnodes)
|
output += "\t%s:\t%s\n" % ("device nodes", self.devnodes)
|
||||||
output += "\tflags:\t\t"
|
output += "\tflags:\t\t"
|
||||||
for funcname in [ "storage", "md_raid", "partitionable", "luks",
|
for funcname in [ func for func in dir(self)
|
||||||
"lvm_pv", "lvm_lv"]:
|
if func.startswith("is_") and callable(getattr(self, func))]:
|
||||||
if getattr(self, "is_%s" % funcname)():
|
if getattr(self, funcname)():
|
||||||
output += "%s " % funcname
|
output += "%s " % funcname[3:]
|
||||||
output += "\n"
|
output += "\n"
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
class BlockdeviceCache:
|
||||||
|
"""manage cached results of blockdevce queries
|
||||||
|
|
||||||
|
the cache expires every 60 seconds or as soon as CACHE_MONITOR_FILE changes
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.values = {}
|
||||||
|
self.expires = None
|
||||||
|
self.partitions_save = None
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
|
||||||
|
def reset(self, link=None):
|
||||||
|
"""empty the cache and reset the expire time
|
||||||
|
"""
|
||||||
|
if not link:
|
||||||
|
self.values = {}
|
||||||
|
try:
|
||||||
|
self.partitions_save = file(CACHE_MONITOR_FILE).read()
|
||||||
|
except IOError, err_msg:
|
||||||
|
LOGGER.warning("Failed to read '%s': %s" % \
|
||||||
|
(CACHE_MONITOR_FILE, err_msg))
|
||||||
|
self.partitions_save = ""
|
||||||
|
self.expires = int(time.time()) + CACHE_EXPIRE_SECONDS
|
||||||
|
else:
|
||||||
|
## we do no reset the expire date
|
||||||
|
self.set(link, {})
|
||||||
|
|
||||||
|
|
||||||
|
def __is_expired(self):
|
||||||
|
"""check if the cache is expired
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if (file(CACHE_MONITOR_FILE).read() != self.partitions_save) or \
|
||||||
|
(self.expires < int(time.time())):
|
||||||
|
return True
|
||||||
|
except IOError:
|
||||||
|
LOGGER.warning("Failed to read '%s': %s" % \
|
||||||
|
(CACHE_MONITOR_FILE, err_msg))
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get(self, link):
|
||||||
|
"""return a cached value
|
||||||
|
|
||||||
|
"link" is an array of the hierachie of the accessed item
|
||||||
|
e.g. link = ["blockdevices", "hda"]
|
||||||
|
return None if the value is not in the cache or if CACHE_ENABLED is False
|
||||||
|
"""
|
||||||
|
if not CACHE_ENABLED:
|
||||||
|
return None
|
||||||
|
if self.__is_expired():
|
||||||
|
self.reset()
|
||||||
|
## walk down the tree
|
||||||
|
ref = self.values
|
||||||
|
for element in link:
|
||||||
|
if element in ref:
|
||||||
|
ref = ref[element]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
return ref
|
||||||
|
|
||||||
|
|
||||||
|
def set(self, link, item):
|
||||||
|
"""store an item in the cache
|
||||||
|
|
||||||
|
"link" is an array of the hierachie of the accessed item
|
||||||
|
e.g. link = ["blockdevices", "hda"]
|
||||||
|
"""
|
||||||
|
if not CACHE_ENABLED:
|
||||||
|
return
|
||||||
|
## walk down the tree
|
||||||
|
ref = self.values
|
||||||
|
for element in link[:-1]:
|
||||||
|
if not element in ref:
|
||||||
|
## create a non-existing sub element
|
||||||
|
ref[element] = {}
|
||||||
|
ref = ref[element]
|
||||||
|
## store the item
|
||||||
|
ref[link[-1]] = item
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_blockdevice(dev,
|
def get_blockdevice(dev,
|
||||||
sysblock_dir=DEFAULT_SYSBLOCK_DIR,
|
sysblock_dir=DEFAULT_SYSBLOCK_DIR,
|
||||||
devnode_dir=DEFAULT_DEVNODE_DIR):
|
devnode_dir=DEFAULT_DEVNODE_DIR):
|
||||||
|
@ -401,16 +710,18 @@ def get_blockdevice(dev,
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
devname = os.path.basename(devdir)
|
devname = os.path.basename(devdir)
|
||||||
dev = _get_cached_value(["blockdevices", devname])
|
cache_link = ["blockdevices", devname]
|
||||||
|
dev = CACHE.get(cache_link)
|
||||||
if dev is None:
|
if dev is None:
|
||||||
dev = Blockdevice(devdir, sysblock_dir, devnode_dir)
|
dev = Blockdevice(devdir, sysblock_dir, devnode_dir)
|
||||||
_set_cached_value(["blockdevices", devname], dev)
|
CACHE.set(cache_link, dev)
|
||||||
return dev
|
return dev
|
||||||
|
|
||||||
|
|
||||||
def find_blockdevices(top_dir):
|
def find_blockdevices(top_dir):
|
||||||
|
|
||||||
cached = _get_cached_value(["blockdevice_dirs", top_dir])
|
cache_link = ["blockdevice_dirs", top_dir]
|
||||||
|
cached = CACHE.get(cache_link)
|
||||||
if not cached is None:
|
if not cached is None:
|
||||||
return cached[:]
|
return cached[:]
|
||||||
|
|
||||||
|
@ -431,98 +742,44 @@ def find_blockdevices(top_dir):
|
||||||
fnames.remove(fname)
|
fnames.remove(fname)
|
||||||
|
|
||||||
os.path.walk(top_dir, look4dev_dirs, 'dev')
|
os.path.walk(top_dir, look4dev_dirs, 'dev')
|
||||||
_set_cached_value(["blockdevice_dirs", top_dir], dev_dirs)
|
CACHE.set(cache_link, dev_dirs)
|
||||||
return dev_dirs[:]
|
return dev_dirs[:]
|
||||||
|
|
||||||
|
|
||||||
def find_lvm_pv():
|
def find_lvm_pv():
|
||||||
"""return the blockdevice names of all physical LVM volumes
|
"""return the blockdevice names of all physical LVM volumes
|
||||||
"""
|
"""
|
||||||
cached = _get_cached_value(["lvm", "pv"])
|
cache_link = ["lvm", "pv"]
|
||||||
|
cached = CACHE.get(cache_link)
|
||||||
if not cached is None:
|
if not cached is None:
|
||||||
return cached[:]
|
return cached[:]
|
||||||
|
|
||||||
#TODO: should we check, if LVM is supported at all?
|
|
||||||
# e.g. by checking the existence of pvdisplay?
|
|
||||||
prefs = _load_preferences()
|
prefs = _load_preferences()
|
||||||
result = None
|
result = None
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
shell = False,
|
shell = False,
|
||||||
stdout = subprocess.PIPE,
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE,
|
||||||
args = [ prefs["Programs"]["super"],
|
args = [ prefs["Programs"]["super"],
|
||||||
prefs["Programs"]["CryptoBoxRootActions"],
|
prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
"program", "pvdisplay" ])
|
"program", "pvdisplay" ])
|
||||||
proc.wait()
|
proc.wait()
|
||||||
except OSError, err_msg:
|
except OSError, err_msg:
|
||||||
# TODO: add a logging warning
|
LOGGER.info("Failed to call 'pvdisplay' via 'super': %s" % err_msg)
|
||||||
result = []
|
result = []
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
# TODO: add a logging warning
|
LOGGER.info("Execution of 'pvdisplay' failed: %s" % \
|
||||||
|
proc.stderr.read().strip())
|
||||||
result = []
|
result = []
|
||||||
if result is None:
|
if result is None:
|
||||||
result = []
|
result = []
|
||||||
for line in proc.stdout.readlines():
|
for line in proc.stdout.readlines():
|
||||||
result.append(line.split(":", 1)[0].strip())
|
result.append(line.split(":", 1)[0].strip())
|
||||||
_set_cached_value(["lvm", "pv"], result)
|
CACHE.set(cache_link, result)
|
||||||
return result[:]
|
return result[:]
|
||||||
|
|
||||||
|
|
||||||
def _get_cached_value(link):
|
|
||||||
"""return a cached value
|
|
||||||
|
|
||||||
"link" is an array of the hierachie of the accessed item
|
|
||||||
e.g. link = ["blockdevices", "hda"]
|
|
||||||
return None if the value is not in the cache or if USE_CACHE is False
|
|
||||||
"""
|
|
||||||
if not USE_CACHE:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if "expires" in CACHED_VALUES:
|
|
||||||
if CACHED_VALUES["expires"] < int(time.time()):
|
|
||||||
reset_cache()
|
|
||||||
else:
|
|
||||||
__reset_cache_timer()
|
|
||||||
|
|
||||||
ref = CACHED_VALUES
|
|
||||||
for element in link:
|
|
||||||
if element in ref:
|
|
||||||
ref = ref[element]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
return ref
|
|
||||||
|
|
||||||
|
|
||||||
def reset_cache():
|
|
||||||
## refresh the cache
|
|
||||||
for item in CACHED_VALUES:
|
|
||||||
CACHED_VALUES[item] = {}
|
|
||||||
__reset_cache_timer()
|
|
||||||
|
|
||||||
|
|
||||||
def __reset_cache_timer():
|
|
||||||
CACHED_VALUES["expires"] = int(time.time()) + CACHE_EXPIRE_SECONDS
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _set_cached_value(link, item):
|
|
||||||
"""store an item in the cache
|
|
||||||
|
|
||||||
"link" is an array of the hierachie of the accessed item
|
|
||||||
e.g. link = ["blockdevices", "hda"]
|
|
||||||
"""
|
|
||||||
if not USE_CACHE:
|
|
||||||
return
|
|
||||||
ref = CACHED_VALUES
|
|
||||||
for element in link[:-1]:
|
|
||||||
if not element in ref:
|
|
||||||
## create a non-existing sub element
|
|
||||||
ref[element] = {}
|
|
||||||
ref = ref[element]
|
|
||||||
## store the item
|
|
||||||
ref[link[-1]] = item
|
|
||||||
|
|
||||||
|
|
||||||
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:
|
||||||
|
@ -540,6 +797,10 @@ def _load_preferences():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## initialize cache
|
||||||
|
CACHE = BlockdeviceCache()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
## list the properties of all available devices
|
## list the properties of all available devices
|
||||||
## this is just for testing purposes
|
## this is just for testing purposes
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright 2006 sense.lab e.V.
|
# Copyright 02006-02007 sense.lab e.V.
|
||||||
#
|
#
|
||||||
# This file is part of the CryptoBox.
|
# This file is part of the CryptoBox.
|
||||||
#
|
#
|
||||||
|
@ -55,6 +55,10 @@ class CryptoBoxContainer:
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, device, cbox):
|
def __init__(self, device, cbox):
|
||||||
|
"""initialize the container
|
||||||
|
|
||||||
|
"device" is a cryptobox.core.blockdevice object
|
||||||
|
"""
|
||||||
self.device = device
|
self.device = device
|
||||||
self.cbox = cbox
|
self.cbox = cbox
|
||||||
self.uuid = None
|
self.uuid = None
|
||||||
|
@ -149,7 +153,7 @@ class CryptoBoxContainer:
|
||||||
e.g.: /dev/hdc1
|
e.g.: /dev/hdc1
|
||||||
Available since: 0.3.0
|
Available since: 0.3.0
|
||||||
"""
|
"""
|
||||||
return self.device
|
return self.device.devnodes[0]
|
||||||
|
|
||||||
|
|
||||||
def get_type(self):
|
def get_type(self):
|
||||||
|
@ -198,8 +202,7 @@ class CryptoBoxContainer:
|
||||||
an error is indicated by "-1"
|
an error is indicated by "-1"
|
||||||
Available since: 0.3.0
|
Available since: 0.3.0
|
||||||
"""
|
"""
|
||||||
import cryptobox.core.tools as cbxtools
|
return self.device.size
|
||||||
return cbxtools.get_blockdevice_size(self.device)
|
|
||||||
|
|
||||||
|
|
||||||
def reset_object(self):
|
def reset_object(self):
|
||||||
|
@ -208,6 +211,7 @@ class CryptoBoxContainer:
|
||||||
this is especially useful after changing the type via 'create'
|
this is especially useful after changing the type via 'create'
|
||||||
Available since: 0.3.0
|
Available since: 0.3.0
|
||||||
"""
|
"""
|
||||||
|
self.device.reset()
|
||||||
self.uuid = self.__get_uuid()
|
self.uuid = self.__get_uuid()
|
||||||
self.cont_type = self.__get_type_of_partition()
|
self.cont_type = self.__get_type_of_partition()
|
||||||
self.fs_type = self.__get_fs_type()
|
self.fs_type = self.__get_fs_type()
|
||||||
|
@ -277,7 +281,7 @@ class CryptoBoxContainer:
|
||||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
"program", "cryptsetup",
|
"program", "cryptsetup",
|
||||||
"luksAddKey",
|
"luksAddKey",
|
||||||
self.device,
|
self.device.devnodes[0],
|
||||||
"--batch-mode"])
|
"--batch-mode"])
|
||||||
proc.stdin.write("%s\n%s" % (oldpw, newpw))
|
proc.stdin.write("%s\n%s" % (oldpw, newpw))
|
||||||
(output, errout) = proc.communicate()
|
(output, errout) = proc.communicate()
|
||||||
|
@ -302,7 +306,7 @@ class CryptoBoxContainer:
|
||||||
self.cbox.prefs["Programs"]["cryptsetup"],
|
self.cbox.prefs["Programs"]["cryptsetup"],
|
||||||
"--batch-mode",
|
"--batch-mode",
|
||||||
"luksDelKey",
|
"luksDelKey",
|
||||||
self.device,
|
self.device.devnodes[0],
|
||||||
"%d" % (keyslot, )])
|
"%d" % (keyslot, )])
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
|
@ -318,7 +322,7 @@ class CryptoBoxContainer:
|
||||||
while it is being formatted or similar.
|
while it is being formatted or similar.
|
||||||
Available since: 0.3.1
|
Available since: 0.3.1
|
||||||
"""
|
"""
|
||||||
return self.cbox.get_device_busy_state(self.device)
|
return self.cbox.get_device_busy_state(self.device.name)
|
||||||
|
|
||||||
|
|
||||||
def set_busy(self, new_state, timeout=300):
|
def set_busy(self, new_state, timeout=300):
|
||||||
|
@ -328,7 +332,7 @@ class CryptoBoxContainer:
|
||||||
The timeout is optional and defaults to five minutes.
|
The timeout is optional and defaults to five minutes.
|
||||||
Available since: 0.3.1
|
Available since: 0.3.1
|
||||||
"""
|
"""
|
||||||
self.cbox.set_device_busy_state(self.device, new_state, timeout)
|
self.cbox.set_device_busy_state(self.device.name, new_state, timeout)
|
||||||
|
|
||||||
|
|
||||||
## ****************** internal stuff *********************
|
## ****************** internal stuff *********************
|
||||||
|
@ -358,56 +362,13 @@ class CryptoBoxContainer:
|
||||||
def __get_uuid(self):
|
def __get_uuid(self):
|
||||||
"""Retrieve the uuid of the container device.
|
"""Retrieve the uuid of the container device.
|
||||||
"""
|
"""
|
||||||
if self.__get_type_of_partition() == CONTAINERTYPES["luks"]:
|
guess = self.device.uuid
|
||||||
guess = self.__get_luks_uuid()
|
|
||||||
else:
|
|
||||||
guess = self.__get_non_luks_uuid()
|
|
||||||
## did we get a valid value?
|
## did we get a valid value?
|
||||||
if guess:
|
if guess:
|
||||||
return guess
|
return guess
|
||||||
else:
|
else:
|
||||||
## emergency default value
|
## emergency default value
|
||||||
return self.device.replace(os.path.sep, "_")
|
return self.device.name
|
||||||
|
|
||||||
|
|
||||||
def __get_luks_uuid(self):
|
|
||||||
"""get uuid for luks devices"""
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
shell = False,
|
|
||||||
stdout = subprocess.PIPE,
|
|
||||||
stderr = subprocess.PIPE,
|
|
||||||
args = [self.cbox.prefs["Programs"]["cryptsetup"],
|
|
||||||
"luksUUID",
|
|
||||||
self.device])
|
|
||||||
(stdout, stderr) = proc.communicate()
|
|
||||||
if proc.returncode != 0:
|
|
||||||
self.cbox.log.info("could not retrieve luks uuid (%s): %s",
|
|
||||||
(self.device, stderr.strip()))
|
|
||||||
return None
|
|
||||||
return stdout.strip()
|
|
||||||
|
|
||||||
|
|
||||||
def __get_non_luks_uuid(self):
|
|
||||||
"""return UUID for ext2/3 and vfat filesystems"""
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
shell=False,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE,
|
|
||||||
args=[self.cbox.prefs["Programs"]["blkid"],
|
|
||||||
"-s", "UUID",
|
|
||||||
"-o", "value",
|
|
||||||
"-c", os.devnull,
|
|
||||||
"-w", os.devnull,
|
|
||||||
self.device])
|
|
||||||
(stdout, stderr) = proc.communicate()
|
|
||||||
## execution failed?
|
|
||||||
if proc.returncode != 0:
|
|
||||||
self.cbox.log.info("retrieving of partition type (" + str(self.device) \
|
|
||||||
+ ") via 'blkid' failed: " + str(stderr.strip()) \
|
|
||||||
+ " - maybe it is encrypted?")
|
|
||||||
return None
|
|
||||||
## return output of blkid
|
|
||||||
return stdout.strip()
|
|
||||||
|
|
||||||
|
|
||||||
def __get_type_of_partition(self):
|
def __get_type_of_partition(self):
|
||||||
|
@ -415,7 +376,7 @@ class CryptoBoxContainer:
|
||||||
|
|
||||||
see cryptobox.core.container.CONTAINERTYPES
|
see cryptobox.core.container.CONTAINERTYPES
|
||||||
"""
|
"""
|
||||||
if self.__is_luks_partition():
|
if self.device.is_luks():
|
||||||
return CONTAINERTYPES["luks"]
|
return CONTAINERTYPES["luks"]
|
||||||
type_of_partition = self.__get_type_id_of_partition()
|
type_of_partition = self.__get_type_id_of_partition()
|
||||||
if type_of_partition in FSTYPES["plain"]:
|
if type_of_partition in FSTYPES["plain"]:
|
||||||
|
@ -436,7 +397,7 @@ class CryptoBoxContainer:
|
||||||
"-o", "value",
|
"-o", "value",
|
||||||
"-c", os.devnull,
|
"-c", os.devnull,
|
||||||
"-w", os.devnull,
|
"-w", os.devnull,
|
||||||
self.device ])
|
self.device.devnodes[0] ])
|
||||||
(stdout, stderr) = proc.communicate()
|
(stdout, stderr) = proc.communicate()
|
||||||
if proc.returncode == 0:
|
if proc.returncode == 0:
|
||||||
## we found a uuid
|
## we found a uuid
|
||||||
|
@ -454,13 +415,14 @@ class CryptoBoxContainer:
|
||||||
def __get_fs_type(self):
|
def __get_fs_type(self):
|
||||||
"returns the filesystem used on a container"
|
"returns the filesystem used on a container"
|
||||||
## should we handle device mapping or plain device
|
## should we handle device mapping or plain device
|
||||||
if self.__is_luks_partition() and self.name:
|
if self.device.is_luks() and self.name:
|
||||||
|
#TODO: replace this by self.device.holders ...
|
||||||
container = os.path.join(self.__dmDir, self.name)
|
container = os.path.join(self.__dmDir, self.name)
|
||||||
## can't determine fs while encrypted
|
## can't determine fs while encrypted
|
||||||
if not self.is_mounted():
|
if not self.is_mounted():
|
||||||
return "unavailable"
|
return "unavailable"
|
||||||
else:
|
else:
|
||||||
container = self.device
|
container = self.device.devnodes[0]
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
shell = False,
|
shell = False,
|
||||||
stdout = subprocess.PIPE,
|
stdout = subprocess.PIPE,
|
||||||
|
@ -479,22 +441,6 @@ class CryptoBoxContainer:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def __is_luks_partition(self):
|
|
||||||
"check if the given device is a luks partition"
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
shell = False,
|
|
||||||
stdin = None,
|
|
||||||
stdout = subprocess.PIPE,
|
|
||||||
stderr = subprocess.PIPE,
|
|
||||||
args = [
|
|
||||||
self.cbox.prefs["Programs"]["cryptsetup"],
|
|
||||||
"--batch-mode",
|
|
||||||
"isLuks",
|
|
||||||
self.device])
|
|
||||||
proc.wait()
|
|
||||||
return proc.returncode == 0
|
|
||||||
|
|
||||||
|
|
||||||
def __get_mount_point(self):
|
def __get_mount_point(self):
|
||||||
"return the name of the mountpoint of this volume"
|
"return the name of the mountpoint of this volume"
|
||||||
return os.path.join(self.cbox.prefs["Locations"]["MountParentDir"], self.name)
|
return os.path.join(self.cbox.prefs["Locations"]["MountParentDir"], self.name)
|
||||||
|
@ -525,7 +471,7 @@ class CryptoBoxContainer:
|
||||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
"program", "cryptsetup",
|
"program", "cryptsetup",
|
||||||
"luksOpen",
|
"luksOpen",
|
||||||
self.device,
|
self.device.devnodes[0],
|
||||||
self.name,
|
self.name,
|
||||||
"--batch-mode"])
|
"--batch-mode"])
|
||||||
proc.stdin.write(password)
|
proc.stdin.write(password)
|
||||||
|
@ -621,7 +567,7 @@ class CryptoBoxContainer:
|
||||||
self.cbox.prefs["Programs"]["super"],
|
self.cbox.prefs["Programs"]["super"],
|
||||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
"program", "mount",
|
"program", "mount",
|
||||||
self.device,
|
self.device.devnodes[0],
|
||||||
self.__get_mount_point()])
|
self.__get_mount_point()])
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
|
@ -691,7 +637,7 @@ class CryptoBoxContainer:
|
||||||
args = [
|
args = [
|
||||||
self.cbox.prefs["Programs"]["nice"],
|
self.cbox.prefs["Programs"]["nice"],
|
||||||
self.cbox.prefs["Programs"]["mkfs"],
|
self.cbox.prefs["Programs"]["mkfs"],
|
||||||
"-t", fs_type, self.device])
|
"-t", fs_type, self.device.devnodes[0]])
|
||||||
loc_data.proc.wait()
|
loc_data.proc.wait()
|
||||||
## wait to allow error detection
|
## wait to allow error detection
|
||||||
if loc_data.proc.returncode == 0:
|
if loc_data.proc.returncode == 0:
|
||||||
|
@ -711,7 +657,7 @@ class CryptoBoxContainer:
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
## if the thread exited very fast, then it failed
|
## if the thread exited very fast, then it failed
|
||||||
if not bg_task.isAlive():
|
if not bg_task.isAlive():
|
||||||
raise CBCreateError("formatting of device (%s) failed out " % self.device \
|
raise CBCreateError("formatting of device (%s) failed out " % self.device.devnodes[0] \
|
||||||
+ "of unknown reasons")
|
+ "of unknown reasons")
|
||||||
|
|
||||||
|
|
||||||
|
@ -736,7 +682,7 @@ class CryptoBoxContainer:
|
||||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
"program", "cryptsetup",
|
"program", "cryptsetup",
|
||||||
"luksFormat",
|
"luksFormat",
|
||||||
self.device,
|
self.device.devnodes[0],
|
||||||
"--batch-mode",
|
"--batch-mode",
|
||||||
"--cipher", self.cbox.prefs["Main"]["DefaultCipher"],
|
"--cipher", self.cbox.prefs["Main"]["DefaultCipher"],
|
||||||
"--iter-time", "2000"])
|
"--iter-time", "2000"])
|
||||||
|
@ -757,7 +703,7 @@ class CryptoBoxContainer:
|
||||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||||
"program", "cryptsetup",
|
"program", "cryptsetup",
|
||||||
"luksOpen",
|
"luksOpen",
|
||||||
self.device,
|
self.device.devnodes[0],
|
||||||
self.name,
|
self.name,
|
||||||
"--batch-mode"])
|
"--batch-mode"])
|
||||||
proc.stdin.write(password)
|
proc.stdin.write(password)
|
||||||
|
@ -808,7 +754,7 @@ class CryptoBoxContainer:
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
## if the thread exited very fast, then it failed
|
## if the thread exited very fast, then it failed
|
||||||
if not bg_task.isAlive():
|
if not bg_task.isAlive():
|
||||||
raise CBCreateError("formatting of device (%s) failed out " % self.device \
|
raise CBCreateError("formatting of device (%s) failed out " % self.device.devnodes[0] \
|
||||||
+ "of unknown reasons")
|
+ "of unknown reasons")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright 2006 sense.lab e.V.
|
# Copyright 02006-02007 sense.lab e.V.
|
||||||
#
|
#
|
||||||
# This file is part of the CryptoBox.
|
# This file is part of the CryptoBox.
|
||||||
#
|
#
|
||||||
|
@ -27,9 +27,8 @@ __revision__ = "$Id$"
|
||||||
import sys
|
import sys
|
||||||
import cryptobox.core.container as cbxContainer
|
import cryptobox.core.container as cbxContainer
|
||||||
from cryptobox.core.exceptions import CBEnvironmentError, CBConfigUndefinedError
|
from cryptobox.core.exceptions import CBEnvironmentError, CBConfigUndefinedError
|
||||||
import re
|
import cryptobox.core.blockdevice as blockdevice
|
||||||
import os
|
import os
|
||||||
import cryptobox.core.tools as cbxTools
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
@ -154,7 +153,8 @@ class CryptoBox:
|
||||||
"""
|
"""
|
||||||
self.log.debug("rereading container list")
|
self.log.debug("rereading container list")
|
||||||
self.__containers = []
|
self.__containers = []
|
||||||
for device in cbxTools.get_available_partitions():
|
blockdevice.CACHE.reset()
|
||||||
|
for device in blockdevice.Blockdevices().get_storage_devices():
|
||||||
if self.is_device_allowed(device) and not self.is_config_partition(device):
|
if self.is_device_allowed(device) and not self.is_config_partition(device):
|
||||||
self.__containers.append(cbxContainer.CryptoBoxContainer(device, self))
|
self.__containers.append(cbxContainer.CryptoBoxContainer(device, self))
|
||||||
## sort by container name
|
## sort by container name
|
||||||
|
@ -204,49 +204,30 @@ class CryptoBox:
|
||||||
|
|
||||||
The check is done by comparing the label of the filesystem with a string.
|
The check is done by comparing the label of the filesystem with a string.
|
||||||
"""
|
"""
|
||||||
proc = subprocess.Popen(
|
return device.label == self.prefs["Main"]["ConfigVolumeLabel"]
|
||||||
shell = False,
|
|
||||||
stdout = subprocess.PIPE,
|
|
||||||
stderr = subprocess.PIPE,
|
|
||||||
args = [
|
|
||||||
self.prefs["Programs"]["blkid"],
|
|
||||||
"-c", os.path.devnull,
|
|
||||||
"-o", "value",
|
|
||||||
"-s", "LABEL",
|
|
||||||
device])
|
|
||||||
(output, error) = proc.communicate()
|
|
||||||
return output.strip() == self.prefs["Main"]["ConfigVolumeLabel"]
|
|
||||||
|
|
||||||
|
|
||||||
def is_device_allowed(self, devicename):
|
def is_device_allowed(self, device):
|
||||||
"""check if a device is white-listed for being used as cryptobox containers
|
"""check if a device is white-listed for being used as cryptobox containers
|
||||||
|
|
||||||
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
|
||||||
devicename = os.path.abspath(devicename)
|
|
||||||
if not os.access(devicename, os.R_OK):
|
|
||||||
self.log.debug("Skipping device without read permissions: %s" % devicename)
|
|
||||||
return False
|
|
||||||
if not os.access(devicename, os.W_OK):
|
|
||||||
self.log.debug("Skipping device without write permissions: %s" % devicename)
|
|
||||||
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]
|
||||||
for a_dev in allowed:
|
for devnode in device.devnodes:
|
||||||
if not a_dev:
|
if [ a_dev for a_dev in allowed if devnode.startswith(a_dev) ]:
|
||||||
continue
|
if os.access(devnode, os.R_OK | os.W_OK):
|
||||||
## double dots are not allowed (e.g. /dev/ide/../sda)
|
self.log.debug("Adding valid device: %s" % devnode)
|
||||||
if re.search("/\.\./", devicename):
|
## move the device to the first position
|
||||||
continue
|
device.devnodes.remove(devnode)
|
||||||
## it is not possible to check for 'realpath' - that does not work
|
device.devnodes.insert(0, devnode)
|
||||||
## for the cryptobox as /dev/ is bind-mounted (real hda-name is /opt/...)
|
|
||||||
if re.search('^%s' % a_dev, devicename):
|
|
||||||
self.log.debug("Adding valid device: %s" % devicename)
|
|
||||||
return True
|
return True
|
||||||
self.log.debug("Skipping device not listed in Main->AllowedDevices: %s" \
|
else:
|
||||||
% devicename)
|
self.log.debug("Skipping device without read and write" \
|
||||||
|
+ "permissions: %s" % device.name)
|
||||||
|
self.log.debug("Skipping unusable device: %s" % device.name)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,7 +250,7 @@ class CryptoBox:
|
||||||
|
|
||||||
def get_container(self, device):
|
def get_container(self, device):
|
||||||
"retrieve the container element for this device"
|
"retrieve the container element for this device"
|
||||||
all = [e for e in self.get_container_list() if e.device == device]
|
all = [e for e in self.get_container_list() if e.device.name == device.name]
|
||||||
if all:
|
if all:
|
||||||
return all[0]
|
return all[0]
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in a new issue