removed dependency on /dev/mapper location from container.py

replaced some functions in container.py with their new blockdevice.py counterparts
move "type_id" detection from container.py to blockdevice.py
reduce calls of "reset" for blockdevices
This commit is contained in:
lars 2007-08-20 11:21:56 +00:00
parent 3224d59dfe
commit 1270b00a5f
2 changed files with 139 additions and 78 deletions

View File

@ -22,6 +22,9 @@
These classes detect and filter available blockdevices.
'''
#TODO: call blkid only once for all devices and scan the result
__revision__ = "$Id$"
@ -111,11 +114,14 @@ class Blockdevice:
self.devnodes = None
self.uuid = None
self.label = None
self.reset()
self.reset(empty_cache=False)
def reset(self):
def reset(self, empty_cache=True):
"""reread the data of the device
usually we will have to reset the cache, too
just in case of first-time initialization, this is not necessary
"""
CACHE.reset(["blockdevice_info", self.name])
self.devnum = self.__get_major_minor()
@ -128,6 +134,7 @@ class Blockdevice:
self.devnodes = self.__get_device_nodes()
self.uuid = self.__get_uuid()
self.label = self.__get_label()
self.type_id = self.__get_type_id()
def is_valid(self):
@ -569,8 +576,49 @@ class Blockdevice:
self.devnodes[0]])
(output, error) = proc.communicate()
except OSError, err_msg:
LOGGER.warning("Failed to call '%s' to determine label: %s" % \
(prefs["Programs"]["blkid"], err_msg))
LOGGER.warning("Failed to call '%s' to determine label for " \
% prefs["Programs"]["blkid"] + "'%s': %s" % \
(self.devnodes[0], err_msg))
return None
if proc.returncode != 0:
LOGGER.warning("Execution of '%s' for '%s' failed: %s" % \
(prefs["Programs"]["blkid"], self.devnodes[0],
error.strip()))
return None
result = output.strip()
if result:
return result
else:
return None
def __get_type_id(self):
"""determine the type id of a filesystem contained in a device
possible results are: ext2, ext3, vfat, reiserfs, swap, ...
return None for errors, empty labels and for luks or non-storage devices
"""
if not self.is_valid():
return None
if self.is_luks():
return None
prefs = _load_preferences()
try:
proc = subprocess.Popen(
shell = False,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
args = [ prefs["Programs"]["blkid"],
"-s", "TYPE",
"-o", "value",
"-c", os.devnull,
"-w", os.devnull,
self.devnodes[0]])
(output, error) = proc.communicate()
except OSError, err_msg:
LOGGER.warning("Failed to call '%s' to determine type id for" \
% prefs["Programs"]["blkid"] + " '%s': %s" % \
(self.devnodes[0], err_msg))
return None
if proc.returncode != 0:
LOGGER.warning("Execution of '%s' for '%s' failed: %s" % \

View File

@ -28,6 +28,7 @@ import os
import re
import time
from cryptobox.core.exceptions import *
import cryptobox.core.blockdevice
CONTAINERTYPES = {
@ -51,8 +52,6 @@ class CryptoBoxContainer:
"""Manage a container of the CryptoBox
"""
__dmDir = "/dev/mapper"
def __init__(self, device, cbox):
"""initialize the container
@ -68,7 +67,7 @@ class CryptoBoxContainer:
self.mount = None
self.umount = None
self.attributes = None
self.reset_object()
self.reset_object(reset_device=False)
def get_name(self):
@ -205,13 +204,15 @@ class CryptoBoxContainer:
return self.device.size
def reset_object(self):
def reset_object(self, reset_device=True):
"""recheck the information about this container
this is especially useful after changing the type via 'create'
the 'device' attribute does not need to be reset during __init__
Available since: 0.3.0
"""
self.device.reset()
if reset_device():
self.device.reset()
self.uuid = self.__get_uuid()
self.cont_type = self.__get_type_of_partition()
self.fs_type = self.__get_fs_type()
@ -243,7 +244,8 @@ class CryptoBoxContainer:
## no exception was raised during creation -> we can continue
## reset the properties (encryption state, ...) of the device
self.reset_object()
## restore the old name (must be after reset_object)
## restore the old name, as the uuid was changed during 'create'
## must happen after reset_object
try:
self.set_name(old_name)
except CBNameIsInUse:
@ -266,6 +268,7 @@ class CryptoBoxContainer:
## return if new and old passwords are the same
if oldpw == newpw:
return
#TODO: why can we do this only for non-mounted volumes?
if self.is_mounted():
raise CBVolumeIsActive("this container is currently active")
## remove any potential open luks mapping
@ -339,13 +342,18 @@ class CryptoBoxContainer:
def __get_name_of_container(self):
"""retrieve the name of the container by querying the database
call this function only for the initial setup of the container object"""
call this function only for the initial setup of the container object
"""
found_name = None
for key in self.cbox.prefs.volumes_db.keys():
if self.cbox.prefs.volumes_db[key]["uuid"] == self.uuid:
found_name = key
## the name may not be equal to the name of another existing device
## otherwise problems regarding the mount directory would arise
if found_name:
return found_name
test_device = cryptobox.core.blockdevice.get_blockdevice(found_name)
if (test_device is None) or (test_device == self.device):
return found_name
## there is no name defined for this uuid - we will propose a good one
prefix = self.cbox.prefs["Main"]["DefaultVolumePrefix"]
unused_found = False
@ -388,62 +396,32 @@ class CryptoBoxContainer:
def __get_type_id_of_partition(self):
"returns the type of the partition (see 'man blkid')"
proc = subprocess.Popen(
shell = False,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
args = [ self.cbox.prefs["Programs"]["blkid"],
"-s", "TYPE",
"-o", "value",
"-c", os.devnull,
"-w", os.devnull,
self.get_device() ])
(stdout, stderr) = proc.communicate()
if proc.returncode == 0:
## we found a uuid
return stdout.strip()
elif proc.returncode == 2:
## failed to find the attribute - no problem
return None
else:
## something strange happened
self.cbox.log.warn("retrieving of partition type via 'blkid' failed: %s" % \
(stderr.strip(), ))
return None
return self.device.type_id
def __get_fs_type(self):
"returns the filesystem used on a container"
## should we handle device mapping or plain device
if self.device.is_luks() and self.name:
#TODO: replace this by self.device.holders ...
container = os.path.join(self.__dmDir, self.name)
## can't determine fs while encrypted
if not self.is_mounted():
return "unavailable"
"""returns the filesystem used on a container
for luks devices: return the type of the encrypted container
return None for invalid device, for non-storage devices, ...
"""
if self.device.is_luks():
## luks devices need special care ...
if self.device.holders:
return cryptobox.core.blockdevice.get_blockdevice(
self.device.holders[0]).type_id
else:
## the encrypted container is not open
return None
else:
container = self.get_device()
proc = subprocess.Popen(
shell = False,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
args = [ self.cbox.prefs["Programs"]["blkid"],
"-s","TYPE",
container ])
(stdout, stderr) = proc.communicate()
if proc.returncode == 0:
return stdout.split("TYPE=")[1]
else:
## if something goes wrong don't dig deeper
self.cbox.log.warn("Filesystem determination (%s) failed: %s" % \
(self.get_device(), stderr.strip()))
return "undetermined"
return
## common (non-luks) devices
return self.device.type_id
def __get_mount_point(self):
"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)
def __mount_luks(self, password):
@ -457,10 +435,12 @@ class CryptoBoxContainer:
if not os.path.exists(self.__get_mount_point()):
self.__create_mount_directory(self.__get_mount_point())
if not os.path.exists(self.__get_mount_point()):
err_msg = "Could not create mountpoint (%s)" % (self.__get_mount_point(), )
err_msg = "Could not create mountpoint (%s)" % \
(self.__get_mount_point(), )
self.cbox.log.error(err_msg)
raise CBMountError(err_msg)
self.cbox.send_event_notification("premount", self.__get_event_args())
self.cbox.send_event_notification("premount",
self.__get_event_args())
proc = subprocess.Popen(
shell = False,
stdin = subprocess.PIPE,
@ -480,6 +460,17 @@ class CryptoBoxContainer:
err_msg = "Could not open the luks mapping: %s" % (errout.strip(), )
self.cbox.log.warn(err_msg)
raise CBMountError(err_msg)
## reset device info (reread self.device.holders)
self.device.reset()
if self.device.holders:
## the decrypted blockdevice is available
plain_device = cryptobox.core.blockdevice.get_blockdevice(
self.device.holders[0]).devnodes[0]
else:
err_msg = "Could not find the plaintext container for " \
+ "'%s': %s" % (self.get_device(), "no hold devices found")
self.cbox.log.warn(err_msg)
raise CBMountError(err_msg)
proc = subprocess.Popen(
shell = False,
stdin = None,
@ -489,20 +480,23 @@ class CryptoBoxContainer:
self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"program", "mount",
os.path.join(self.__dmDir, self.name),
plain_device,
self.__get_mount_point()])
proc.wait()
if proc.returncode != 0:
err_msg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
err_msg = "Could not mount the filesystem: %s" \
% (proc.stderr.read().strip(), )
self.cbox.log.warn(err_msg)
raise CBMountError(err_msg)
## chmod the mount directory to 0777 - this is the easy way to avoid problems
## this only works for ext2/3 - vfat silently ignore it
## chmod the mount directory to 0777
## this is the easy way to avoid problems
## it only works for ext2/3 - vfat silently ignore it
## we mounted vfat partitions with umask=0000
try:
os.chmod(self.__get_mount_point(), 0777)
except OSError:
self.cbox.log.warn("Failed to set write permission for the mount directory")
self.cbox.log.warn("Failed to set write permission for the " \
+ "mount directory")
self.cbox.send_event_notification("postmount", self.__get_event_args())
@ -522,10 +516,14 @@ class CryptoBoxContainer:
self.__get_mount_point()])
proc.wait()
if proc.returncode != 0:
err_msg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), )
err_msg = "Could not umount the filesystem: %s" % \
(proc.stderr.read().strip(), )
self.cbox.log.warn(err_msg)
raise CBUmountError(err_msg)
if os.path.exists(os.path.join(self.__dmDir, self.name)):
## reset device (reread self.device.holders)
self.device.reset()
## are there any dependent devices?
if self.device.holders:
proc = subprocess.Popen(
shell = False,
stdin = None,
@ -574,8 +572,9 @@ class CryptoBoxContainer:
err_msg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
self.cbox.log.warn(err_msg)
raise CBMountError(err_msg)
## chmod the mount directory to 0777 - this is the easy way to avoid problems
## this only works for ext2/3 - vfat silently ignore it
## chmod the mount directory to 0777
## this is the easy way to avoid problems
## it only works for ext2/3 - vfat silently ignore it
## we mounted vfat partitions with umask=0000
try:
os.chmod(self.__get_mount_point(), 0777)
@ -712,8 +711,19 @@ class CryptoBoxContainer:
err_msg = "Could not open the new luks mapping: %s" % (errout.strip(), )
self.cbox.log.error(err_msg)
raise CBCreateError(err_msg)
## reset device info (reread self.device.holders)
self.device.reset()
if self.device.holders:
## the decrypted blockdevice is available
plain_device = cryptobox.core.blockdevice.get_blockdevice(
self.device.holders[0]).devnodes[0]
else:
err_msg = "Could not find the plaintext container for " \
+ "'%s': %s" % (self.get_device(), "no hold devices found")
self.cbox.log.warn(err_msg)
raise CBMountError(err_msg)
def format_luks():
"""This function will get called as a seperate thread.
"""This function will get called as a separate thread.
To avoid the non-sharing cpu distribution between the formatting thread
and the main interface, we fork and let the parent wait for the child.
@ -735,7 +745,7 @@ class CryptoBoxContainer:
self.cbox.prefs["Programs"]["nice"],
self.cbox.prefs["Programs"]["mkfs"],
"-t", fs_type,
os.path.join(self.__dmDir, self.name)])
plain_device ] )
loc_data.proc.wait()
## wait to allow error detection
if loc_data.proc.returncode == 0:
@ -767,15 +777,16 @@ class CryptoBoxContainer:
if (not os.path.islink(abs_dir)) \
and os.path.isdir(abs_dir) \
and (not os.path.ismount(abs_dir)) \
and (os.path.isfile(os.path.join(abs_dir,MOUNT_DIR_MARKER))) \
and (os.path.isfile(os.path.join(abs_dir,
MOUNT_DIR_MARKER))) \
and (len(os.listdir(abs_dir)) == 1):
try:
os.remove(os.path.join(abs_dir, MOUNT_DIR_MARKER))
os.rmdir(abs_dir)
except OSError, err_msg:
## we do not care too much about unclean cleaning ...
self.cbox.log.info("failed to clean a mountpoint (%s): %s" % \
(abs_dir, str(err_msg)))
self.cbox.log.info("failed to clean a mountpoint (%s): %s" \
% (abs_dir, str(err_msg)))
def __create_mount_directory(self, dirname):
@ -787,7 +798,8 @@ class CryptoBoxContainer:
mark_file.close()
except OSError, err_msg:
## we do not care too much about the marking
self.cbox.log.info("failed to mark a mountpoint (%s): %s" % (dirname, str(err_msg)))
self.cbox.log.info("failed to mark a mountpoint (%s): %s" % \
(dirname, str(err_msg)))
def __get_event_args(self):
@ -797,5 +809,6 @@ class CryptoBoxContainer:
"""
type_text = [e for e in CONTAINERTYPES.keys()
if CONTAINERTYPES[e] == self.get_type()][0]
return [self.get_device(), self.get_name(), type_text, self.__get_mount_point()]
return [self.get_device(), self.get_name(), type_text,
self.__get_mount_point()]