plugin interface changed: now we use classes (inherited by CryptoBoxPlugin) instead of plain scripts

added some log entries
use threading module instead of "fork" for background formatting
redirection for "network" plugin fixed
empty return value of plugins defaults to plugin overview page
This commit is contained in:
lars 2006-09-25 12:21:39 +00:00
parent 52ccaeb530
commit 56e954d1c4
11 changed files with 545 additions and 436 deletions

View File

@ -1,49 +1,64 @@
import subprocess import CryptoBoxPlugin
import os
def doAction(hdf, cbox, store=None, year=0, month=0, day=0, hour=0, minute=0): class date(CryptoBoxPlugin.CryptoBoxPlugin):
import datetime
__prepareFormData(hdf, cbox) def doAction(self, store=None, year=0, month=0, day=0, hour=0, minute=0):
if store: import datetime
try: if store:
year, month, day = int(year), int(month), int(day) try:
hour, minute = int(hour), int(minute) year, month, day = int(year), int(month), int(day)
new_date = datetime.datetime(year, month, day, hour, minute) hour, minute = int(hour), int(minute)
except ValueError: new_date = datetime.datetime(year, month, day, hour, minute)
hdf["Data.Warning"] = "Plugins.date.InvalidDate" except ValueError:
self.hdf["Data.Warning"] = "Plugins.date.InvalidDate"
self.__prepareFormData()
return "form_date"
date = "%02d%02d%02d%02d%d" % (month, day, hour, minute, year)
if self.__setDate(date):
self.cbox.log.info("changed date to: %s" % date)
self.hdf["Data.Success"] = "Plugins.date.DateChanged"
return None
else:
## a failure should usually be an invalid date (we do not check it really)
self.cbox.log.info("failed to set date: %s" % date)
self.hdf["Data.Warning"] = "Plugins.date.InvalidDate"
self.__prepareFormData()
return "form_date"
else:
self.__prepareFormData()
return "form_date"
def getStatus(self):
return str(self.__getCurrentDate())
def __prepareFormData(self):
date = self.__getCurrentDate()
self.hdf[self.hdf_prefix + "year"] = date.year
self.hdf[self.hdf_prefix + "month"] = date.month
self.hdf[self.hdf_prefix + "day"] = date.day
self.hdf[self.hdf_prefix + "hour"] = date.hour
self.hdf[self.hdf_prefix + "minute"] = date.minute
def __getCurrentDate(self):
import datetime
return datetime.datetime(2000,1,1).now()
def __setDate(self, date):
import subprocess
import os
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
args = [ args = [
cbox.prefs["Programs"]["super"], self.cbox.prefs["Programs"]["super"],
cbox.prefs["Programs"]["CryptoBoxRootActions"], self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin", "plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"), os.path.join(self.pluginDir, "root_action.py"),
"%02d%02d%02d%02d%d" % (month, day, hour, minute, year)]) date])
proc.communicate() proc.communicate()
if proc.returncode == 0: return proc.returncode == 0
return "form_system"
else:
hdf["Data.Warning"] = "Plugins.date.InvalidDate"
return "form_date"
else:
return "form_date"
def getStatus(cbox):
return str(__getCurrentDate())
def __prepareFormData(hdf, cbox):
date = __getCurrentDate()
hdf["Data.Plugins.date.year"] = date.year
hdf["Data.Plugins.date.month"] = date.month
hdf["Data.Plugins.date.day"] = date.day
hdf["Data.Plugins.date.hour"] = date.hour
hdf["Data.Plugins.date.minute"] = date.minute
def __getCurrentDate():
import datetime
return datetime.datetime(2000,1,1).now()

View File

@ -23,7 +23,14 @@ Text.Months {
12 = December 12 = December
} }
WarningMessage.InvalidDate { SuccessMessage.DateChanged {
Title = Invalid value Title = Date changed
Text = An invalid value for date or time was supplied. Please try again. Text = The date was changed successfully.
}
WarningMessage {
InvalidDate {
Title = Invalid value
Text = An invalid value for date or time was supplied. Please try again.
}
} }

View File

@ -1,20 +1,23 @@
import CryptoBoxPlugin
def doAction(hdf, cbox): class logs(CryptoBoxPlugin.CryptoBoxPlugin):
__prepareFormData(hdf,cbox)
return "show_log" def doAction(self):
self.__prepareFormData()
return "show_log"
def getStatus(cbox): def getStatus(self):
return "%s:%s:%s" % ( return "%s:%s:%s" % (
cbox.prefs["Log"]["Level"], self.cbox.prefs["Log"]["Level"],
cbox.prefs["Log"]["Destination"], self.cbox.prefs["Log"]["Destination"],
cbox.prefs["Log"]["Details"]) self.cbox.prefs["Log"]["Details"])
def __prepareFormData(hdf, cbox): def __prepareFormData(self):
hdf["Data.Plugins.logs.Content"] = __getLogContent(cbox) self.hdf[self.hdf_prefix + "Content"] = self.__getLogContent()
def __getLogContent(cbox, lines=30, maxSize=2000): def __getLogContent(self, lines=30, maxSize=2000):
return "<br/>".join(cbox.getLogData(lines, maxSize)) return "<br/>".join(self.cbox.getLogData(lines, maxSize))

View File

@ -4,7 +4,7 @@ Rank = 30
Title.Network = Network settings Title.Network = Network settings
Button.Network = Update settings Button.Network = Update network settings
Text.IP = Network address Text.IP = Network address

View File

@ -1,71 +1,110 @@
import re
import subprocess import subprocess
import imp
import os import os
import CryptoBoxPlugin
## specify (in seconds), how long we should wait before redirecting and ip change
REDIRECT_DELAY=20
CHANGE_IP_DELAY=5
def doAction(hdf, cbox, store=None, ip1="", ip2="", ip3="", ip4=""): class network(CryptoBoxPlugin.CryptoBoxPlugin):
__prepareFormData(hdf, cbox)
if store: def doAction(self, store=None, redirected="", ip1="", ip2="", ip3="", ip4=""):
try: ## if we were redirected, then we should display the default page
for ip_in in (ip1, ip2, ip3, ip4): if redirected == "1":
if (int(ip_in) < 0) or (int(ip_in) > 255): return None
cbox.log.debug("invalid IP supplied: %s" % str((ip1,ip2,ip3,ip4))) ## request for IP change?
raise ValueError if store:
ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4)) try:
except ValueError: for ip_in in (ip1, ip2, ip3, ip4):
hdf["Data.Warning"] = "Plugins.network.InvalidIP" if (int(ip_in) < 0) or (int(ip_in) > 255):
return "form_system" self.cbox.log.info("invalid IP supplied: %s" % str((ip1,ip2,ip3,ip4)))
if __setIP(cbox, ip): raise ValueError
hdf["Data.Success"] = "Plugins.network.IPChanged" ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4))
hdf["Data.Redirect.URL"] = "" except ValueError:
hdf["Data.Redirect.Delay"] = 30 self.hdf["Data.Warning"] = "Plugins.network.InvalidIP"
return "form_system" return None
if self.__setIP(ip):
self.cbox.log.info("the IP was successfully changed: %s" % ip)
self.hdf["Data.Success"] = "Plugins.network.IPChanged"
self.hdf["Data.Redirect.URL"] = self.__getRedirectDestination(ip)
self.hdf["Data.Redirect.Delay"] = REDIRECT_DELAY
return None
else:
self.cbox.log.warn("failed to change IP address to: %s" % ip)
self.hdf["Data.Warning"] = "Plugins.network.InvalidIP"
self.__prepareFormData()
return "form_network"
else: else:
hdf["Data.Warning"] = "Plugins.network.InvalidIP" ## just show the form
self.__prepareFormData()
return "form_network" return "form_network"
else:
return "form_network"
def getStatus(cbox): def getStatus(self):
return "%d.%d.%d.%d" % __getCurrentIP(cbox) return "%d.%d.%d.%d" % self.__getCurrentIP()
def __prepareFormData(hdf, cbox): def __getRedirectDestionation(self, ip):
(oc1, oc2, oc3, oc4) = __getCurrentIP(cbox) import cherrypy
hdf["Data.Plugins.network.ip.oc1"] = oc1 req = cherrypy.request
hdf["Data.Plugins.network.ip.oc2"] = oc2 dest = ip
hdf["Data.Plugins.network.ip.oc3"] = oc3 base_parts = req.base.split(":")
hdf["Data.Plugins.network.ip.oc4"] = oc4 if len(base_parts) == 3:
dest += ":%s" % base_parts[2]
return dest
def __getCurrentIP(cbox): def __prepareFormData(self):
root_action_plug = imp.load_source("root_action", os.path.join(os.path.dirname(__file__), "root_action.py")) (oc1, oc2, oc3, oc4) = self.__getCurrentIP()
proc = subprocess.Popen( self.hdf[self.hdf_prefix + "ip.oc1"] = oc1
shell = False, self.hdf[self.hdf_prefix + "ip.oc2"] = oc2
stdout = subprocess.PIPE, self.hdf[self.hdf_prefix + "ip.oc3"] = oc3
args = [ self.hdf[self.hdf_prefix + "ip.oc4"] = oc4
root_action_plug.IFCONFIG_BIN,
root_action_plug.IFACE])
(output, error) = proc.communicate()
if proc.returncode != 0: return (0,0,0,0)
match = re.search(u'inet [\w]+:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s',output)
if match:
return tuple([int(e) for e in match.groups()])
else:
return (0,0,0,0)
def __setIP(cbox, ip): def __getCurrentIP(self):
proc = subprocess.Popen( import re
shell = False, import imp
args = [ ## load some values from the root_action.py script
cbox.prefs["Programs"]["super"], root_action_plug = imp.load_source("root_action", os.path.join(self.pluginDir, "root_action.py"))
cbox.prefs["Programs"]["CryptoBoxRootActions"], ## get the current IP of the network interface
"plugin", proc = subprocess.Popen(
os.path.join(os.path.dirname(__file__), "root_action.py"), shell = False,
ip]) stdout = subprocess.PIPE,
proc.communicate() args = [
return proc.returncode == 0 root_action_plug.IFCONFIG_BIN,
root_action_plug.IFACE])
(output, error) = proc.communicate()
if proc.returncode != 0: return (0,0,0,0)
## this regex matches the four numbers of the IP
match = re.search(u'inet [\w]+:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s',output)
if match:
## use the previously matched numbers
return tuple([int(e) for e in match.groups()])
else:
return (0,0,0,0)
def __setIP(self, ip):
import threading
## call the root_action script after some seconds - so we can deliver the page before
def delayedIPchange():
import time
time.sleep(CHANGE_IP_DELAY)
proc = subprocess.Popen(
shell = False,
args = [
self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(self.pluginDir, "root_action.py"),
ip])
proc.communicate()
return
thread = threading.Thread()
thread.run = delayedIPchange
thread.setDaemon(True)
thread.start()
# TODO: how could we guess, if it failed?
return True

View File

@ -25,6 +25,7 @@ Text {
Size = Size (MB) Size = Size (MB)
SelectDevice = Choose a disk for partitioning SelectDevice = Choose a disk for partitioning
WarningMessage = If you continue, you will destroy all data on the choosen disk. Please be careful! WarningMessage = If you continue, you will destroy all data on the choosen disk. Please be careful!
ProgressInfo = Progress of formatting:
} }
SuccessMessage { SuccessMessage {

View File

@ -2,308 +2,328 @@ import subprocess
import os import os
import logging import logging
import CryptoBoxTools import CryptoBoxTools
import CryptoBoxPlugin
PartTypes = { class partition(CryptoBoxPlugin.CryptoBoxPlugin):
"windows" : ["0xC", "vfat"],
"linux" : ["L", "ext3"]}
ConfigPartition = { PartTypes = {
"size" : 5, # size of configuration partition (if necessary) in MB "windows" : ["0xC", "vfat"],
"type" : "L", "linux" : ["L", "ext3"]}
"fs" : "ext2"}
logger = logging.getLogger("CryptoBox") ConfigPartition = {
"size" : 5, # size of configuration partition (if necessary) in MB
"type" : "L",
"fs" : "ext2"}
def doAction(hdf, cbox, **args): def doAction(self, **args):
try: ## retrieve some values from 'args' - defaults are empty
step = args["step"] self.withConfigPartition = self.__isWithConfigPartition(args)
del args["step"] self.device = self.__getSelectedDevice(args)
except KeyError: self.deviceSize = self.__getAvailableDeviceSize(self.device)
step = "select_device"
if step == "add_partition":
return __actionAddPartition(hdf, cbox, args)
if step == "del_partition":
return __actionDelPartition(hdf, cbox, args)
elif step == "finish":
return __actionFinish(hdf, cbox, args)
else: # for "select_device" and for invalid targets
return __actionSelectDevice(hdf, cbox, args)
def getStatus(cbox):
return "TODO"
def __isDeviceValid(device, cbox):
if not cbox.isDeviceAllowed(device):
return False
if not device in CryptoBoxTools.getParentBlockDevices():
return False
return True
def __isDeviceBusy(device, cbox):
"""check if the device (or one of its partitions) is mounted"""
# TODO: the config partition is ignored, as it is not part of the container list - that is not good
import re
for c in cbox.getContainerList():
if re.match(device + "\d*$", c.getDevice()):
if c.isMounted(): return True
return False
def __actionSelectDevice(hdf, cbox, args):
block_devices = [e
for e in CryptoBoxTools.getParentBlockDevices()
if cbox.isDeviceAllowed(e)]
counter = 0
for a in block_devices:
hdf["Data.Plugins.partition.BlockDevices.%d" % counter] = a
cbox.log.debug("found a suitable block device: %s" % a)
counter += 1
if __withConfigPartition(args):
hdf["Data.Plugins.partition.CreateConfigPartition"] = "1"
## there is no disk available
if not block_devices:
hdf["Data.Warning"] = "Plugins.partition.NoDisksAvailable"
return "select_device"
def __actionAddPartition(hdf, cbox, args):
try:
device = args["block_device"]
except KeyError:
return __actionSelectDevice(hdf, cbox, args)
if not __isDeviceValid(device, cbox): return __actionSelectDevice(hdf, cbox, args)
if __isDeviceBusy(device, cbox):
hdf["Data.Warning"] = "Plugins.partition.DiskIsBusy"
return __actionSelectDevice(hdf, cbox, args)
size = __getAvailableDeviceSize(device, __withConfigPartition(args))
hdf["Data.Plugins.partition.Device"] = device
hdf["Data.Plugins.partition.Device.Size"] = size
parts = __getPartitionsFromArgs(hdf, args, size)
__setPartitionData(hdf, parts, size, __withConfigPartition(args))
return "set_partitions"
def __actionDelPartition(hdf, cbox, args):
try:
device = args["block_device"]
part_num = int(args["del_num"])
except (TypeError,KeyError):
return __actionSelectDevice(hdf, cbox, args)
if not __isDeviceValid(device, cbox): return __actionSelectDevice(hdf, cbox, args)
if __isDeviceBusy(device, cbox):
hdf["Data.Warning"] = "Plugins.partition.DiskIsBusy"
return __actionSelectDevice(hdf, cbox, args)
size = __getAvailableDeviceSize(device, __withConfigPartition(args))
hdf["Data.Plugins.partition.Device"] = device
hdf["Data.Plugins.partition.Device.Size"] = size
parts = __getPartitionsFromArgs(hdf, args, size)
## valid partition number to be deleted?
if part_num < len(parts):
del parts[part_num]
else:
return __actionSelectDevice(hdf, cbox, args)
__setPartitionData(hdf, parts, size, __withConfigPartition(args))
return "set_partitions"
def __actionFinish(hdf, cbox, args):
try:
device = args["block_device"]
except KeyError:
return __actionSelectDevice(hdf, cbox, args)
if not __isDeviceValid(device, cbox): return __actionSelectDevice(hdf, cbox, args)
if __isDeviceBusy(device, cbox):
hdf["Data.Warning"] = "Plugins.partition.DiskIsBusy"
return __actionSelectDevice(hdf, cbox, args)
size = __getAvailableDeviceSize(device, __withConfigPartition(args))
parts = __getPartitionsFromArgs(hdf, args, size)
if parts:
if not __runFDisk(cbox, device, parts, __withConfigPartition(args)):
hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
return __actionAddPartition(hdf, cbox, args)
else:
if __formatPartitions(cbox, device, parts, __withConfigPartition(args)):
hdf["Data.Success"] = "Plugins.partition.Partitioned"
else:
hdf["Data.Warning"] = "Plugins.partition.FormattingFailed"
cbox.reReadContainerList()
return "form_system"
else:
return __actionSelectDevice(hdf, cbox, args)
def __setPartitionData(hdf, parts, size, withConfigPartition):
availSize = size
i = 0
for part in parts:
logger.debug(part)
hdf["Data.Plugins.partition.Parts.%d.Size" % i] = part["size"]
hdf["Data.Plugins.partition.Parts.%d.Type" % i] = part["type"]
availSize -= part["size"]
i += 1
hdf["Data.Plugins.partition.availSize"] = availSize
if withConfigPartition:
hdf["Data.Plugins.partition.CreateConfigPartition"] = "1"
for t in PartTypes.keys():
hdf["Data.Plugins.partition.Types.%s" % t] = t
def __getPartitionsFromArgs(hdf, args, maxSize):
parts = []
done = False
availSize = maxSize
i = -1
while not done:
i += 1
try: try:
size = int(args["part%d_size" % i]) step = args["step"]
partType = args["part%d_type" % i] del args["step"]
if int(size) > availSize:
hdf["Data.Warning"] = "Plugins.partition.PartitionTooBig"
continue
if int(size) < 10:
hdf["Data.Warning"] = "Plugins.partition.PartitionTooSmall"
continue
if not partType in PartTypes.keys(): continue
parts.append({"size":size, "type":partType})
availSize -= size
except TypeError:
pass
except KeyError: except KeyError:
done = True step = "select_device"
return parts ## no (or invalid) device was supplied
if not self.device:
step == "select_device"
if step == "add_partition":
return self.__actionAddPartition(args)
if step == "del_partition":
return self.__actionDelPartition(args)
elif step == "finish":
return self.__actionFinish(args)
else: # for "select_device" and for invalid targets
return self.__actionSelectDevice(args)
def __getAvailableDeviceSize(device, withConfigPartition): def getStatus(self):
"""calculate the available size (MB) of the device return "%s / %s / %s" % (self.device, self.deviceSize, self.withConfigPartition)
also consider a (possible) configuration partition"""
rdev = os.stat(device).st_rdev
minor = os.minor(rdev) def __getSelectedDevice(self, args):
major = os.major(rdev)
for f in file("/proc/partitions"):
try: try:
elements = f.split() device = args["block_device"]
if len(elements) != 4: continue except KeyError:
if (int(elements[0]) == major) and (int(elements[1]) == minor): return None
deviceSize = int(elements[2])/1024 if not self.__isDeviceValid(device):
if withConfigPartition: deviceSize -= ConfigPartition["size"] return None
return deviceSize if self.__isDeviceBusy(device):
except ValueError: self.hdf["Data.Warning"] = "Plugins.partition.DiskIsBusy"
pass return None
return 0 return device
def __withConfigPartition(args): def __isDeviceValid(self, device):
try: if not device:
if args["create_config_partition"]: return False
createConfig = True if not self.cbox.isDeviceAllowed(device):
return False
if not device in CryptoBoxTools.getParentBlockDevices():
return False
return True
def __isDeviceBusy(self, device):
"""check if the device (or one of its partitions) is mounted"""
# TODO: the config partition is ignored, as it is not part of the container list - that is not good
import re
for c in self.cbox.getContainerList():
if re.match(device + "\d*$", c.getDevice()):
if c.isMounted(): return True
return False
def __actionSelectDevice(self, args):
block_devices = [e
for e in CryptoBoxTools.getParentBlockDevices()
if self.cbox.isDeviceAllowed(e)]
counter = 0
for a in block_devices:
self.hdf[self.hdf_prefix + "BlockDevices.%d" % counter] = a
self.cbox.log.debug("found a suitable block device: %s" % a)
counter += 1
if self.withConfigPartition:
self.hdf[self.hdf_prefix + "CreateConfigPartition"] = "1"
## there is no disk available
if not block_devices:
self.hdf["Data.Warning"] = "Plugins.partition.NoDisksAvailable"
return "select_device"
def __actionAddPartition(self, args):
self.hdf[self.hdf_prefix + "Device"] = self.device
self.hdf[self.hdf_prefix + "Device.Size"] = self.deviceSize
parts = self.__getPartitionsFromArgs(args)
self.__setPartitionData(parts)
return "set_partitions"
def __actionDelPartition(self, args):
try:
part_num = int(args["del_num"])
except (TypeError,KeyError):
return self.__actionAddPartition(args)
self.hdf[self.hdf_prefix + "Device"] = self.device
self.hdf[self.hdf_prefix + "Device.Size"] = self.deviceSize
parts = self.__getPartitionsFromArgs(args)
## valid partition number to be deleted?
if part_num < len(parts):
del parts[part_num]
else: else:
return self.__actionAddPartition(args)
self.__setPartitionData(parts)
return "set_partitions"
def __actionFinish(self, args):
parts = self.__getPartitionsFromArgs(args)
if parts:
self.__setPartitionData(parts)
if not self.__runFDisk(parts):
self.hdf["Data.Warning"] = "Plugins.partition.PartitioningFailed"
return self.__actionAddPartition(args)
else:
# TODO: will we use the "yield"-style? If yes, then remove these messages (success and warning)
#if self.__formatPartitions(parts):
# self.hdf["Data.Success"] = "Plugins.partition.Partitioned"
#else:
# self.hdf["Data.Warning"] = "Plugins.partition.FormattingFailed"
"""
tricky problem: if the device was partitioned, then a created config partition is still part of the containerlist, as the label is not checked again - very ugly!!! So we will call reReadContainerList after formatting the last partition - see below
"""
self.cbox.reReadContainerList()
def result_generator():
counter = 0
## initialize the generator
formatPart_gen = self.__formatPartitions(parts)
while counter < len(parts):
## first part: get the device name
yield formatPart_gen.next()
counter += 1
## second part: do the real formatting of a partition
result = formatPart_gen.next()
## after the first partiton, we can reRead the containerList (as the possible config partition was already created)
if self.withConfigPartition and (counter == 1):
## important: reRead the containerList
self.cbox.reReadContainerList()
## return the result
yield result
return {
"template": "show_format_progress",
"generator": result_generator}
else:
return self.__actionAddPartition(args)
def __setPartitionData(self, parts):
availSize = self.deviceSize
i = 0
for part in parts:
self.cbox.log.debug(part)
self.hdf[self.hdf_prefix + "Parts.%d.Size" % i] = part["size"]
self.hdf[self.hdf_prefix + "Parts.%d.Type" % i] = part["type"]
availSize -= part["size"]
i += 1
self.hdf[self.hdf_prefix + "availSize"] = availSize
if self.withConfigPartition:
self.hdf[self.hdf_prefix + "CreateConfigPartition"] = "1"
for t in self.PartTypes.keys():
self.hdf[self.hdf_prefix + "Types.%s" % t] = t
def __getPartitionsFromArgs(self, args):
parts = []
done = False
availSize = self.deviceSize
i = -1
while not done:
i += 1
try:
size = int(args["part%d_size" % i])
partType = args["part%d_type" % i]
if int(size) > availSize:
self.hdf["Data.Warning"] = "Plugins.partition.PartitionTooBig"
continue
if int(size) < 10:
self.hdf["Data.Warning"] = "Plugins.partition.PartitionTooSmall"
continue
if not partType in self.PartTypes.keys(): continue
parts.append({"size":size, "type":partType})
availSize -= size
except TypeError:
pass
except KeyError:
done = True
return parts
def __getAvailableDeviceSize(self, device):
"""calculate the available size (MB) of the device
also consider a (possible) configuration partition"""
if not device: return 0
rdev = os.stat(device).st_rdev
minor = os.minor(rdev)
major = os.major(rdev)
for f in file("/proc/partitions"):
try:
elements = f.split()
if len(elements) != 4: continue
if (int(elements[0]) == major) and (int(elements[1]) == minor):
deviceSize = int(elements[2])/1024
if self.withConfigPartition:
deviceSize -= self.ConfigPartition["size"]
return deviceSize
except ValueError:
pass
return 0
def __isWithConfigPartition(self, args):
try:
if args["create_config_partition"]:
createConfig = True
else:
createConfig = False
except KeyError:
createConfig = False createConfig = False
except KeyError: return createConfig
createConfig = False
return createConfig
def __runFDisk(cbox, device, parts, withConfigPartition): def __runFDisk(self, parts):
## check if the device is completely filled (to avoid some empty last blocks) ## check if the device is completely filled (to avoid some empty last blocks)
avail_size = __getAvailableDeviceSize(device, withConfigPartition) avail_size = self.deviceSize
for d in parts: avail_size -= d["size"] for d in parts: avail_size -= d["size"]
isFilled = avail_size == 0 isFilled = avail_size == 0
proc = subprocess.Popen(
shell = False,
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
args = [
cbox.prefs["Programs"]["super"],
cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"),
"partition",
device])
for line in __getSFDiskLayout(parts, withConfigPartition, isFilled):
proc.stdin.write(line + "\n")
(output, error) = proc.communicate()
if proc.returncode != 0: logger.debug("partitioning failed: %s" % error)
return proc.returncode == 0
def __getSFDiskLayout(paramParts, withConfigPartition, isFilled):
parts = paramParts[:]
## first a (possible) configuration partition - so it will be reusable
if withConfigPartition:
## fill the main table (including a config partition)
yield ",%d,%s" % (ConfigPartition["size"], ConfigPartition["type"])
## one primary partition
yield ",%d,%s,*" % (parts[0]["size"], PartTypes[parts[0]["type"]][0])
del parts[0]
## no extended partition, if there is only one disk
if not parts: return
## an extended container for the rest
yield ",,E"
## an empty partition in main table
yield ";"
## maybe another empty partition if there is no config partition
if not withConfigPartition: yield ";"
while parts:
if isFilled and (len(parts) == 1):
yield ",,%s" % (PartTypes[parts[0]["type"]][0],)
else:
yield ",%d,%s" % (parts[0]["size"], PartTypes[parts[0]["type"]][0])
del parts[0]
def __formatPartitions(cbox, device, paramParts, withConfigPartition):
success = True
parts = paramParts[:]
part_num = 1
## maybe a config partition?
if withConfigPartition:
dev_name = device + str(part_num)
logger.info("formatting config partition (%s)" % dev_name)
if __formatOnePartition(cbox, dev_name, ConfigPartition["fs"]):
__setLabelOfPartition(cbox, dev_name, cbox.prefs["Main"]["ConfigVolumeLabel"])
else:
success = False
part_num += 1
## the first data partition
dev_name = device + str(part_num)
partType = PartTypes[parts[0]["type"]][1]
logger.info("formatting partition (%s) as '%s'" % (dev_name, partType))
if not __formatOnePartition(cbox, dev_name, partType):
success = False
del parts[0]
## other data partitions
part_num = 5
while parts:
dev_name = device + str(part_num)
partType = PartTypes[parts[0]["type"]][1]
logger.info("formatting partition (%s) as '%s'" % (dev_name, partType))
if not __formatOnePartition(cbox, dev_name, partType):
success = False
part_num += 1
del parts[0]
return success
def __formatOnePartition(cbox, dev_name, type):
import time, sys
child_pid = os.fork()
## we run formatting as a parallel thread
## TODO: the parent thread still waits for the last child - that is not good for big harddisks
if child_pid == 0:
## we are the child process
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = subprocess.PIPE,
stdout = subprocess.PIPE, stdout = subprocess.PIPE,
stderr = subprocess.PIPE, stderr = subprocess.PIPE,
args = [ args = [
cbox.prefs["Programs"]["super"], self.cbox.prefs["Programs"]["super"],
cbox.prefs["Programs"]["CryptoBoxRootActions"], self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"),
"partition",
self.device])
for line in self.__getSFDiskLayout(parts, isFilled):
proc.stdin.write(line + "\n")
(output, error) = proc.communicate()
if proc.returncode != 0: self.cbox.log.debug("partitioning failed: %s" % error)
return proc.returncode == 0
def __getSFDiskLayout(self, paramParts, isFilled):
parts = paramParts[:]
## first a (possible) configuration partition - so it will be reusable
if self.withConfigPartition:
## fill the main table (including a config partition)
yield ",%d,%s" % (self.ConfigPartition["size"], self.ConfigPartition["type"])
## one primary partition
yield ",%d,%s,*" % (parts[0]["size"], self.PartTypes[parts[0]["type"]][0])
del parts[0]
## no extended partition, if there is only one disk
if not parts: return
## an extended container for the rest
yield ",,E"
## an empty partition in main table
yield ";"
## maybe another empty partition if there is no config partition
if not self.withConfigPartition: yield ";"
while parts:
if isFilled and (len(parts) == 1):
yield ",,%s" % (self.PartTypes[parts[0]["type"]][0],)
else:
yield ",%d,%s" % (parts[0]["size"], self.PartTypes[parts[0]["type"]][0])
del parts[0]
def __formatPartitions(self, paramParts):
import threading
parts = paramParts[:]
part_num = 1
## maybe a config partition?
if self.withConfigPartition:
dev_name = self.device + str(part_num)
self.cbox.log.info("formatting config partition (%s)" % dev_name)
if self.__formatOnePartition(dev_name, self.ConfigPartition["fs"]):
self.__setLabelOfPartition(dev_name, self.cbox.prefs["Main"]["ConfigVolumeLabel"])
part_num += 1
## the first data partition
dev_name = self.device + str(part_num)
partType = self.PartTypes[parts[0]["type"]][1]
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType))
yield dev_name
if self.__formatOnePartition(dev_name, partType):
yield "OK"
else:
yield "<b>Failed!</b>"
del parts[0]
## other data partitions
part_num = 5
while parts:
dev_name = self.device + str(part_num)
partType = self.PartTypes[parts[0]["type"]][1]
self.cbox.log.info("formatting partition (%s) as '%s'" % (dev_name, partType))
yield dev_name
if self.__formatOnePartition(dev_name, partType):
yield "OK"
else:
yield "<b>Failed!</b>"
part_num += 1
del parts[0]
return
def __formatOnePartition(self, dev_name, type):
proc = subprocess.Popen(
shell = False,
args = [
self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin", "plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"), os.path.join(os.path.dirname(__file__), "root_action.py"),
"format", "format",
@ -311,37 +331,29 @@ def __formatOnePartition(cbox, dev_name, type):
type]) type])
(output, error) = proc.communicate() (output, error) = proc.communicate()
if proc.returncode != 0: if proc.returncode != 0:
logger.warn("failed to create filesystem on %s: %s" % (dev_name, error)) self.cbox.log.warn("failed to create filesystem on %s: %s" % (dev_name, error))
sys.exit(1) return False
else: else:
sys.exit(0) return True
else:
time.sleep(1)
(pid, exit_state) = os.waitpid(child_pid, os.WNOHANG) def __setLabelOfPartition(self, dev_name, label):
if ((pid == 0) and (exit_state == 0)) \ proc = subprocess.Popen(
or ((pid == child_pid) and (exit_state == 0)): shell = False,
return True stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
args = [
self.cbox.prefs["Programs"]["super"],
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"),
"label",
dev_name,
label])
(output, error) = proc.communicate()
if proc.returncode == 0:
return True
else: else:
self.cbox.log.warn("failed to create filesystem on %s: %s" % (dev_name, error))
return False return False
def __setLabelOfPartition(cbox, dev_name, label):
proc = subprocess.Popen(
shell = False,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
args = [
cbox.prefs["Programs"]["super"],
cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"),
"label",
dev_name,
label])
(output, error) = proc.communicate()
if proc.returncode == 0:
return True
else:
logger.warn("failed to create filesystem on %s: %s" % (device + str(part_num), error))
return False

View File

@ -26,14 +26,28 @@ def __partitionDevice(device):
def __formatPartition(device, type): def __formatPartition(device, type):
proc = subprocess.Popen( import time, threading
shell = False, result = True
args = [ def formatting():
MKFS_BIN, proc = subprocess.Popen(
"-t", type, shell = False,
device]) stdin = subprocess.PIPE,
proc.communicate() stdout = subprocess.PIPE,
return proc.returncode == 0 stderr = subprocess.PIPE,
args = [
MKFS_BIN,
"-t", type,
device])
proc.communicate()
## TODO: very ugly way of communication: it assumes, that failures are fast - success is slow
if proc.returncode == 0:
time.sleep(1)
thread = threading.Thread()
thread.setDaemon(True)
thread.run = formatting
thread.start()
time.sleep(0.5)
return thread.isAlive()
def __labelPartition(device, label): def __labelPartition(device, label):

View File

@ -35,7 +35,7 @@
<input type="hidden" name="step" value="add_partition" /> <input type="hidden" name="step" value="add_partition" />
<?cs set: x = subcount(Data.Plugins.partition.Parts) ?> <?cs set: x = subcount(Data.Plugins.partition.Parts) ?>
<td><?cs var:x ?></td> <td><?cs var:x ?></td>
<td><input type="text" name="part<?cs var:x ?>_size" size="8" value="<?cs var:Data.Plugins.partition.availSize ?>" /></td> <td><input type="text" name="part<?cs var:x ?>_size" size="8" value="<?cs var:Data.Plugins.partition.availSize ?>" tabindex="0" /></td>
<td><select name="part<?cs var:x ?>_type" size="0"><?cs each: t = Data.Plugins.partition.Types ?><option <?cs if:t == "windows" ?>selected="selected"<?cs /if ?>><?cs var:t ?></option> <td><select name="part<?cs var:x ?>_type" size="0"><?cs each: t = Data.Plugins.partition.Types ?><option <?cs if:t == "windows" ?>selected="selected"<?cs /if ?>><?cs var:t ?></option>
<?cs /each ?></select></td> <?cs /each ?></select></td>
<td> <td>

View File

@ -0,0 +1,13 @@
<?cs # $Id$ ?>
<h1><?cs var:html_escape(Lang.Plugins.partition.Title.Partition) ?></h1>
<p><?cs var:html_escape(Lang.Plugins.partition.Text.ProgressInfo) ?>
<ul>
<?cs loop: x = #0, subcount(Data.Plugins.partition.Parts)-1, #1 ?>
<li><!-- CONTENT_DUMMY -->:&nbsp;
<!-- CONTENT_DUMMY --></li>
<?cs /loop ?>
</ul>
</p>

View File

@ -5,15 +5,20 @@ The following directory structure is required:
Python code interface: Python code interface:
def doAction(hdf, cbox, store=None, ???): - create a class with the same name as the plugin - it has to inherit CryptoBoxPlugin
- function "doAction":
- this function will get called whenever this plugins is involved in a request - this function will get called whenever this plugins is involved in a request
- all arguments should be optional (e.g. for displaying a form without previous input values) - all arguments should be optional (e.g. for displaying a form without previous input values)
- the argument "store" should be used to process a form submission (just a recommendation) - the argument "store" should be used to process a form submission (just a recommendation)
- if the processing failed for some reason (invalid input, ...), it should manually set the "Data.Warning" (resp. "Data.Error" or "Data.Success") to a value of your choice (preferably you may want to use messages of your namespace (e.g. "Plugins.PLUGINNAME.InvalidInput")) - if the processing failed for some reason (invalid input, ...), it should manually set the "Data.Warning" (resp. "Data.Error" or "Data.Success") to a value of your choice (preferably you may want to use messages of your namespace (e.g. "Plugins.PLUGINNAME.InvalidInput"))
- the return value should be the name of the template that should be displayed after processing (a template file in the plugin directory takes precedence over global template files) - the return value should be the name of the template that should be displayed after processing (a template file in the plugin directory takes precedence over global template files)
- the return value may also be a dictionary with the following elements:
* template: the name of the template file (mandatory)
* generator: a generator object ("yield") - its content will replace every occourence of "<!-- CONTENT_DUMMY -->" in the template (useful for pages that are displayed step by step (as for formatting of filesystems))
- an empty (e.g. None) return value can be used to go return to the plugin page
def def getStatus(cbox): - function "getStatus":
- returns a string, that described a state connected to this plugin (e.g. the current date and time (for the "date" plugin) - returns a string, that describes a state connected to this plugin (e.g. the current date and time (for the "date" plugin))
Language file structure: Language file structure: