make blkid more verbose
fix permission problem during bootup (Closes: #139) add support for partitioning of blockdevices ending in a digit (e.g. raid (md) devices) added fieldset to partition plugin
This commit is contained in:
parent
8e7f0b16a7
commit
1de2ebe176
9 changed files with 92 additions and 62 deletions
|
@ -30,6 +30,7 @@ REMOVE_ENV_SETTINGS = [ "LANG", "LC", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
|
||||||
"LC_MESSAGES", "LC_NUMERIC", "BASH_ENV", "SHELLOPTS" ]
|
"LC_MESSAGES", "LC_NUMERIC", "BASH_ENV", "SHELLOPTS" ]
|
||||||
|
|
||||||
import os, sys
|
import os, sys
|
||||||
|
import signal, atexit
|
||||||
import cryptobox.web.sites
|
import cryptobox.web.sites
|
||||||
from cryptobox.core.exceptions import *
|
from cryptobox.core.exceptions import *
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
@ -66,13 +67,14 @@ except:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
# TODO: change this for the release version [development|production]
|
|
||||||
SERVER_ENVIRONMENT = "production"
|
SERVER_ENVIRONMENT = "production"
|
||||||
|
|
||||||
class CryptoBoxWebserver:
|
class CryptoBoxWebserver:
|
||||||
'''this class starts the cherrypy webserver and serves the single sites'''
|
'''this class starts the cherrypy webserver and serves the single sites'''
|
||||||
|
|
||||||
def __init__(self, opts):
|
def __init__(self, opts):
|
||||||
|
"""Configure cherrypy and check the location of the configuration file
|
||||||
|
"""
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
## check conffile
|
## check conffile
|
||||||
if not os.access(opts.conffile, os.R_OK) or not os.path.isfile(opts.conffile):
|
if not os.access(opts.conffile, os.R_OK) or not os.path.isfile(opts.conffile):
|
||||||
|
@ -98,18 +100,16 @@ class CryptoBoxWebserver:
|
||||||
"staticFilter.on" : True,
|
"staticFilter.on" : True,
|
||||||
"staticFilter.file": os.path.realpath(os.path.join(opts.datadir, 'favicon.ico'))}
|
"staticFilter.file": os.path.realpath(os.path.join(opts.datadir, 'favicon.ico'))}
|
||||||
})
|
})
|
||||||
## drop privileges to run the cryptobox without root permissions
|
|
||||||
self.drop_privileges_temporarily()
|
|
||||||
|
def bootup_cryptobox(self):
|
||||||
## initialize site class
|
## initialize site class
|
||||||
try:
|
try:
|
||||||
cherrypy.root = cryptobox.web.sites.WebInterfaceSites(self.conffile)
|
cherrypy.root = cryptobox.web.sites.WebInterfaceSites(self.conffile)
|
||||||
self.website = cherrypy.root
|
self.website = cherrypy.root
|
||||||
except (CBConfigError,CBEnvironmentError), err_msg:
|
except (CBConfigError,CBEnvironmentError), err_msg:
|
||||||
sys.stderr.write("Error: the CryptoBox is misconfigured - please fix it!\n")
|
sys.stderr.write("Error: the CryptoBox is misconfigured - please fix it!\n")
|
||||||
sys.stderr.write("%s\n" % str(err_msg))
|
raise
|
||||||
sys.exit(1)
|
|
||||||
## restore privileges, as we need them to connect to a low socket (<1024)
|
|
||||||
self.restore_privileges()
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_info(self):
|
def get_user_info(self):
|
||||||
|
@ -132,31 +132,6 @@ class CryptoBoxWebserver:
|
||||||
return (pw_uid, pw_gid, additional_groups)
|
return (pw_uid, pw_gid, additional_groups)
|
||||||
|
|
||||||
|
|
||||||
def drop_privileges_temporarily(self):
|
|
||||||
"""Temporarily drop privileges.
|
|
||||||
"""
|
|
||||||
if self.opts.user is None:
|
|
||||||
return
|
|
||||||
(pw_uid, pw_gid, additional_groups) = self.get_user_info()
|
|
||||||
try:
|
|
||||||
os.setegid(pw_gid)
|
|
||||||
os.seteuid(pw_uid)
|
|
||||||
except OSError, err_msg:
|
|
||||||
sys.stderr.write("Failed to drop privileges temporarily: %s\n" % err_msg)
|
|
||||||
|
|
||||||
|
|
||||||
def restore_privileges(self):
|
|
||||||
"""Restore previously temporarily dropped privileges.
|
|
||||||
"""
|
|
||||||
if self.opts.user is None:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
os.setegid(os.getgid())
|
|
||||||
os.seteuid(os.getuid())
|
|
||||||
except OSError, err_msg:
|
|
||||||
sys.stderr.write("Failed to restore privileges: %s\n" % err_msg)
|
|
||||||
|
|
||||||
|
|
||||||
def change_groups(self):
|
def change_groups(self):
|
||||||
"""Change the groups of the current process to the ones of the given user
|
"""Change the groups of the current process to the ones of the given user
|
||||||
|
|
||||||
|
@ -191,10 +166,13 @@ class CryptoBoxWebserver:
|
||||||
def start(self):
|
def start(self):
|
||||||
try:
|
try:
|
||||||
## first: change the groups (cherrypy.server.start stores the
|
## first: change the groups (cherrypy.server.start stores the
|
||||||
## current setting for creating new threads later
|
## current setting for creating new threads later)
|
||||||
self.change_groups()
|
self.change_groups()
|
||||||
cherrypy.server.start(initOnly=True)
|
cherrypy.server.start(initOnly=True)
|
||||||
self.drop_privileges_permanently()
|
self.drop_privileges_permanently()
|
||||||
|
## this must be done with dropped privileges - otherwise there is
|
||||||
|
## at least a problem with 'blkid' - see bug #139
|
||||||
|
self.bootup_cryptobox()
|
||||||
cherrypy.server.wait_for_http_ready()
|
cherrypy.server.wait_for_http_ready()
|
||||||
except cherrypy._cperror.NotReady, err_msg:
|
except cherrypy._cperror.NotReady, err_msg:
|
||||||
sys.stderr.write("Failed to start CryptoBox: %s\n" % err_msg)
|
sys.stderr.write("Failed to start CryptoBox: %s\n" % err_msg)
|
||||||
|
@ -357,13 +335,29 @@ if __name__ == "__main__":
|
||||||
options = parseOptions()
|
options = parseOptions()
|
||||||
## set umask to 022 (aka 755) - octal value
|
## set umask to 022 (aka 755) - octal value
|
||||||
os.umask(022)
|
os.umask(022)
|
||||||
## initialize the webserver class (before forking to get some error messages)
|
## initialize the webserver class
|
||||||
cbw = CryptoBoxWebserver(options)
|
cbw = CryptoBoxWebserver(options)
|
||||||
## remove some environment settings
|
## remove some environment settings
|
||||||
clean_environment(REMOVE_ENV_SETTINGS)
|
clean_environment(REMOVE_ENV_SETTINGS)
|
||||||
## fork to background before cbw.start() - otherwise we lose the socket
|
## fork to background before cbw.start() - otherwise we lose the socket
|
||||||
if options.background:
|
if options.background:
|
||||||
fork_to_background()
|
fork_to_background()
|
||||||
|
## define the default exit handler
|
||||||
|
def exit_handler(signum, sigframe):
|
||||||
|
if hasattr(cbw, "website"):
|
||||||
|
## are we already up?
|
||||||
|
cbw.website.cbox.log.info("Shutting down ...")
|
||||||
|
cbw.website.cleanup()
|
||||||
|
cherrypy.server.stop()
|
||||||
|
try:
|
||||||
|
os.remove(options.pidfile)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
os._exit(0)
|
||||||
|
## the signal handler gets called by a kill signal (usually in background mode)
|
||||||
|
signal.signal(signal.SIGTERM, exit_handler)
|
||||||
|
## this exit handler gets called by KeyboardInterrupt and similar ones (foreground)
|
||||||
|
atexit.register(exit_handler, None, None)
|
||||||
## start the webserver
|
## start the webserver
|
||||||
try:
|
try:
|
||||||
if options.profile_file:
|
if options.profile_file:
|
||||||
|
@ -375,6 +369,7 @@ if __name__ == "__main__":
|
||||||
sys.stderr.write("Failed to start the CryptoBox webserver!\n")
|
sys.stderr.write("Failed to start the CryptoBox webserver!\n")
|
||||||
sys.stderr.write("%s\n" % str(err_msg))
|
sys.stderr.write("%s\n" % str(err_msg))
|
||||||
sys.stderr.write("Check the log file for details.\n")
|
sys.stderr.write("Check the log file for details.\n")
|
||||||
|
cherrypy.server.stop()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
## redirect stderr to the webserver's logfile
|
## redirect stderr to the webserver's logfile
|
||||||
if options.background:
|
if options.background:
|
||||||
|
@ -384,22 +379,7 @@ if __name__ == "__main__":
|
||||||
os.close(2)
|
os.close(2)
|
||||||
os.open(options.logfile, os.O_APPEND)
|
os.open(options.logfile, os.O_APPEND)
|
||||||
## startup went fine - fork is done - now we may write the pid file
|
## startup went fine - fork is done - now we may write the pid file
|
||||||
## write pid file
|
|
||||||
write_pid_file(options.pidfile)
|
write_pid_file(options.pidfile)
|
||||||
def exit_handler(signum, sigframe):
|
|
||||||
cbw.website.cbox.log.info("Shutting down ...")
|
|
||||||
cbw.website.cleanup()
|
|
||||||
try:
|
|
||||||
os.remove(options.pidfile)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
os._exit(0)
|
|
||||||
## the signal handler gets called by a kill signal (usually in background mode)
|
|
||||||
import signal
|
|
||||||
signal.signal(signal.SIGTERM, exit_handler)
|
|
||||||
## this exit handler gets called by KeyboardInterrupt and similar ones (foreground)
|
|
||||||
import atexit
|
|
||||||
atexit.register(exit_handler, None, None)
|
|
||||||
## this will never exit - one of the above exit handlers will get triggered
|
## this will never exit - one of the above exit handlers will get triggered
|
||||||
cherrypy.server.block()
|
cherrypy.server.block()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# comma separated list of possible prefixes for accesible devices
|
# comma separated list of possible prefixes for accesible devices
|
||||||
# beware: .e.g "/dev/hd" grants access to _all_ harddisks
|
# beware: .e.g "/dev/hd" grants access to _all_ harddisks
|
||||||
AllowedDevices = /dev/loop, /dev/ubdb
|
AllowedDevices = /dev/loop, /dev/ubdb, /dev/md_d127
|
||||||
|
|
||||||
# use separate config partition? (1=yes / 0=no)
|
# use separate config partition? (1=yes / 0=no)
|
||||||
UseConfigPartition = 1
|
UseConfigPartition = 1
|
||||||
|
|
7
debian/changelog
vendored
7
debian/changelog
vendored
|
@ -1,3 +1,10 @@
|
||||||
|
cryptobox (0.3.4-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* fixed uid handling during bootup (Closes: '139)
|
||||||
|
* added support for partitioning of raid devices
|
||||||
|
|
||||||
|
-- Lars Kruse <devel@sumpfralle.de> Sat, 17 Feb 2007 11:03:41 +0100
|
||||||
|
|
||||||
cryptobox (0.3.3-1) unstable; urgency=low
|
cryptobox (0.3.3-1) unstable; urgency=low
|
||||||
|
|
||||||
* new upstream release
|
* new upstream release
|
||||||
|
|
|
@ -25,6 +25,7 @@ __revision__ = "$Id"
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import logging
|
import logging
|
||||||
import cryptobox.core.tools as cbox_tools
|
import cryptobox.core.tools as cbox_tools
|
||||||
import cryptobox.plugins.base
|
import cryptobox.plugins.base
|
||||||
|
@ -53,7 +54,6 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
def do_action(self, **args):
|
def do_action(self, **args):
|
||||||
"""Show the partitioning form and execute the requested action.
|
"""Show the partitioning form and execute the requested action.
|
||||||
"""
|
"""
|
||||||
import re
|
|
||||||
## load default hdf values
|
## load default hdf values
|
||||||
self.__prepare_dataset()
|
self.__prepare_dataset()
|
||||||
## retrieve some values from 'args' - defaults are empty
|
## retrieve some values from 'args' - defaults are empty
|
||||||
|
@ -455,14 +455,14 @@ 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.blockdevice + str(part_num)
|
dev_name = self.__get_partition_name(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.blockdevice + str(part_num)
|
dev_name = self.__get_partition_name(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)
|
||||||
|
@ -470,7 +470,7 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
## other data partitions
|
## other data partitions
|
||||||
part_num = 5
|
part_num = 5
|
||||||
while parts:
|
while parts:
|
||||||
dev_name = self.blockdevice + str(part_num)
|
dev_name = self.__get_partition_name(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,6 +480,21 @@ class partition(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def __get_partition_name(self, blockdev, number):
|
||||||
|
"""Return the name of a specific partition of a device
|
||||||
|
|
||||||
|
"""
|
||||||
|
## do we need to put a "p" between name and number?
|
||||||
|
## TODO: should we check for existence?
|
||||||
|
if re.search("[0-9]$", blockdev):
|
||||||
|
## blockdev endswith a digit - we need a 'p'
|
||||||
|
return "%sp%d" % (blockdev, number)
|
||||||
|
else:
|
||||||
|
## no 'p' necessary
|
||||||
|
return "%s%d" % (blockdev, number)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def __format_one_partition(self, dev_name, fs_type):
|
def __format_one_partition(self, dev_name, fs_type):
|
||||||
"""Format a single partition
|
"""Format a single partition
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
<?cs # $Id$ ?>
|
<?cs # $Id$ ?>
|
||||||
|
|
||||||
<?cs call:show_plugin_title() ?>
|
|
||||||
<?cs call:handle_messages() ?>
|
<?cs call:handle_messages() ?>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
<?cs call:show_plugin_icon() ?>
|
||||||
|
<?cs var:html_escape(Lang.Plugins.partition.Title) ?>
|
||||||
|
</legend>
|
||||||
|
|
||||||
<?cs call:show_help(Lang.Plugins.partition.Help.Partitioning) ?>
|
<?cs call:show_help(Lang.Plugins.partition.Help.Partitioning) ?>
|
||||||
|
|
||||||
<?cs if:subcount(Data.Plugins.partition.BlockDevices) > 0 ?>
|
<?cs if:subcount(Data.Plugins.partition.BlockDevices) > 0 ?>
|
||||||
|
@ -38,5 +43,7 @@
|
||||||
|
|
||||||
<?cs /if ?>
|
<?cs /if ?>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<?cs # a warning will be displayed if there are no disks available ?>
|
<?cs # a warning will be displayed if there are no disks available ?>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
<?cs # $Id$ ?>
|
<?cs # $Id$ ?>
|
||||||
|
|
||||||
<?cs call:show_plugin_title() ?>
|
|
||||||
<?cs call:handle_messages() ?>
|
<?cs call:handle_messages() ?>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
<?cs call:show_plugin_icon() ?>
|
||||||
|
<?cs var:html_escape(Lang.Plugins.partition.Title) ?>
|
||||||
|
</legend>
|
||||||
|
|
||||||
<?cs # show nothing if the harddisk is not partitionable (e.g. still active) ?>
|
<?cs # show nothing if the harddisk is not partitionable (e.g. still active) ?>
|
||||||
<?cs if:(Data.Plugins.partition.availSize > 0) || (subcount(Data.Plugins.partition.Parts) > 0) ?>
|
<?cs if:(Data.Plugins.partition.availSize > 0) || (subcount(Data.Plugins.partition.Parts) > 0) ?>
|
||||||
|
|
||||||
|
@ -94,3 +99,5 @@
|
||||||
|
|
||||||
<?cs /if ?>
|
<?cs /if ?>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
|
|
@ -10,5 +10,5 @@ __all__ = ['core', 'web', 'plugins', 'tests']
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
|
||||||
__version__ = "0.3.3"
|
__version__ = "0.3.4"
|
||||||
|
|
||||||
|
|
|
@ -253,18 +253,30 @@ class CryptoBoxSettings:
|
||||||
|
|
||||||
def get_available_partitions(self):
|
def get_available_partitions(self):
|
||||||
"""returns a sequence of found config partitions"""
|
"""returns a sequence of found config partitions"""
|
||||||
|
self.log.debug("Retrieving available configuration partitions ...")
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
shell = False,
|
shell = False,
|
||||||
stdout = subprocess.PIPE,
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE,
|
||||||
args = [
|
args = [
|
||||||
self.prefs["Programs"]["blkid"],
|
self.prefs["Programs"]["blkid"],
|
||||||
"-c", os.path.devnull,
|
"-c", os.path.devnull,
|
||||||
"-t", "LABEL=%s" % self.prefs["Main"]["ConfigVolumeLabel"] ])
|
"-t", "LABEL=%s" % self.prefs["Main"]["ConfigVolumeLabel"] ])
|
||||||
(output, error) = proc.communicate()
|
(output, error) = proc.communicate()
|
||||||
|
if proc.returncode == 2:
|
||||||
|
self.log.info("No configuration partitions found")
|
||||||
|
return []
|
||||||
|
elif proc.returncode == 4:
|
||||||
|
self.log.warn("Failed to call 'blkid' for unknown reasons.")
|
||||||
|
return []
|
||||||
|
elif proc.returncode == 0:
|
||||||
if output:
|
if output:
|
||||||
return [e.strip().split(":", 1)[0] for e in output.splitlines()]
|
return [e.strip().split(":", 1)[0] for e in output.splitlines()]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
else:
|
||||||
|
self.log.warn("Unknown exit code of 'blkid': %d - %s" \
|
||||||
|
% (proc.returncode, error))
|
||||||
|
|
||||||
|
|
||||||
def prepare_partition(self):
|
def prepare_partition(self):
|
||||||
|
|
|
@ -46,10 +46,12 @@ def get_available_partitions():
|
||||||
## ignore lines with: invalid minor/major or extend partitions (size=1)
|
## ignore lines with: invalid minor/major or extend partitions (size=1)
|
||||||
if re.search('^[0-9]*$', p_major) and \
|
if re.search('^[0-9]*$', p_major) and \
|
||||||
re.search('^[0-9]*$', p_minor) and (p_size != "1"):
|
re.search('^[0-9]*$', p_minor) and (p_size != "1"):
|
||||||
p_parent = re.sub('[1-9]?[0-9]$', '', p_device)
|
## 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 p_parent == p_device:
|
||||||
if [e for e in ret_list
|
if [e for e in ret_list
|
||||||
if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]:
|
if re.search('^' + p_parent + 'p?[1-9]?[0-9]$', e)]:
|
||||||
## major partition - its children are already in the list
|
## major partition - its children are already in the list
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in a new issue