diff --git a/pythonrewrite/plugins/date/date.py b/pythonrewrite/plugins/date/date.py index 2502075..99f705a 100644 --- a/pythonrewrite/plugins/date/date.py +++ b/pythonrewrite/plugins/date/date.py @@ -1,49 +1,64 @@ -import subprocess -import os +import CryptoBoxPlugin -def doAction(hdf, cbox, store=None, year=0, month=0, day=0, hour=0, minute=0): - import datetime - __prepareFormData(hdf, cbox) - if store: - try: - year, month, day = int(year), int(month), int(day) - hour, minute = int(hour), int(minute) - new_date = datetime.datetime(year, month, day, hour, minute) - except ValueError: - hdf["Data.Warning"] = "Plugins.date.InvalidDate" +class date(CryptoBoxPlugin.CryptoBoxPlugin): + + def doAction(self, store=None, year=0, month=0, day=0, hour=0, minute=0): + import datetime + if store: + try: + year, month, day = int(year), int(month), int(day) + hour, minute = int(hour), int(minute) + new_date = datetime.datetime(year, month, day, hour, minute) + 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( shell = False, args = [ - cbox.prefs["Programs"]["super"], - cbox.prefs["Programs"]["CryptoBoxRootActions"], + self.cbox.prefs["Programs"]["super"], + self.cbox.prefs["Programs"]["CryptoBoxRootActions"], "plugin", - os.path.join(os.path.dirname(__file__), "root_action.py"), - "%02d%02d%02d%02d%d" % (month, day, hour, minute, year)]) + os.path.join(self.pluginDir, "root_action.py"), + date]) proc.communicate() - if 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() + return proc.returncode == 0 diff --git a/pythonrewrite/plugins/date/lang/en.hdf b/pythonrewrite/plugins/date/lang/en.hdf index 17d2b02..a9c9fb0 100644 --- a/pythonrewrite/plugins/date/lang/en.hdf +++ b/pythonrewrite/plugins/date/lang/en.hdf @@ -23,7 +23,14 @@ Text.Months { 12 = December } -WarningMessage.InvalidDate { - Title = Invalid value - Text = An invalid value for date or time was supplied. Please try again. +SuccessMessage.DateChanged { + Title = Date changed + Text = The date was changed successfully. +} + +WarningMessage { + InvalidDate { + Title = Invalid value + Text = An invalid value for date or time was supplied. Please try again. + } } diff --git a/pythonrewrite/plugins/logs/logs.py b/pythonrewrite/plugins/logs/logs.py index ff40e46..5950c1f 100644 --- a/pythonrewrite/plugins/logs/logs.py +++ b/pythonrewrite/plugins/logs/logs.py @@ -1,20 +1,23 @@ +import CryptoBoxPlugin -def doAction(hdf, cbox): - __prepareFormData(hdf,cbox) - return "show_log" +class logs(CryptoBoxPlugin.CryptoBoxPlugin): + + def doAction(self): + self.__prepareFormData() + return "show_log" -def getStatus(cbox): - return "%s:%s:%s" % ( - cbox.prefs["Log"]["Level"], - cbox.prefs["Log"]["Destination"], - cbox.prefs["Log"]["Details"]) + def getStatus(self): + return "%s:%s:%s" % ( + self.cbox.prefs["Log"]["Level"], + self.cbox.prefs["Log"]["Destination"], + self.cbox.prefs["Log"]["Details"]) -def __prepareFormData(hdf, cbox): - hdf["Data.Plugins.logs.Content"] = __getLogContent(cbox) + def __prepareFormData(self): + self.hdf[self.hdf_prefix + "Content"] = self.__getLogContent() -def __getLogContent(cbox, lines=30, maxSize=2000): - return "
".join(cbox.getLogData(lines, maxSize)) + def __getLogContent(self, lines=30, maxSize=2000): + return "
".join(self.cbox.getLogData(lines, maxSize)) diff --git a/pythonrewrite/plugins/network/lang/en.hdf b/pythonrewrite/plugins/network/lang/en.hdf index bd60bf7..4fef621 100644 --- a/pythonrewrite/plugins/network/lang/en.hdf +++ b/pythonrewrite/plugins/network/lang/en.hdf @@ -4,7 +4,7 @@ Rank = 30 Title.Network = Network settings -Button.Network = Update settings +Button.Network = Update network settings Text.IP = Network address diff --git a/pythonrewrite/plugins/network/network.py b/pythonrewrite/plugins/network/network.py index 82a4e5b..55001b4 100644 --- a/pythonrewrite/plugins/network/network.py +++ b/pythonrewrite/plugins/network/network.py @@ -1,71 +1,110 @@ -import re import subprocess -import imp 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=""): - __prepareFormData(hdf, cbox) - if store: - try: - for ip_in in (ip1, ip2, ip3, ip4): - if (int(ip_in) < 0) or (int(ip_in) > 255): - cbox.log.debug("invalid IP supplied: %s" % str((ip1,ip2,ip3,ip4))) - raise ValueError - ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4)) - except ValueError: - hdf["Data.Warning"] = "Plugins.network.InvalidIP" - return "form_system" - if __setIP(cbox, ip): - hdf["Data.Success"] = "Plugins.network.IPChanged" - hdf["Data.Redirect.URL"] = "" - hdf["Data.Redirect.Delay"] = 30 - return "form_system" +class network(CryptoBoxPlugin.CryptoBoxPlugin): + + def doAction(self, store=None, redirected="", ip1="", ip2="", ip3="", ip4=""): + ## if we were redirected, then we should display the default page + if redirected == "1": + return None + ## request for IP change? + if store: + try: + for ip_in in (ip1, ip2, ip3, ip4): + if (int(ip_in) < 0) or (int(ip_in) > 255): + self.cbox.log.info("invalid IP supplied: %s" % str((ip1,ip2,ip3,ip4))) + raise ValueError + ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4)) + except ValueError: + self.hdf["Data.Warning"] = "Plugins.network.InvalidIP" + 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: - hdf["Data.Warning"] = "Plugins.network.InvalidIP" + ## just show the form + self.__prepareFormData() return "form_network" - else: - return "form_network" -def getStatus(cbox): - return "%d.%d.%d.%d" % __getCurrentIP(cbox) + def getStatus(self): + return "%d.%d.%d.%d" % self.__getCurrentIP() -def __prepareFormData(hdf, cbox): - (oc1, oc2, oc3, oc4) = __getCurrentIP(cbox) - hdf["Data.Plugins.network.ip.oc1"] = oc1 - hdf["Data.Plugins.network.ip.oc2"] = oc2 - hdf["Data.Plugins.network.ip.oc3"] = oc3 - hdf["Data.Plugins.network.ip.oc4"] = oc4 + def __getRedirectDestionation(self, ip): + import cherrypy + req = cherrypy.request + dest = ip + base_parts = req.base.split(":") + if len(base_parts) == 3: + dest += ":%s" % base_parts[2] + return dest -def __getCurrentIP(cbox): - root_action_plug = imp.load_source("root_action", os.path.join(os.path.dirname(__file__), "root_action.py")) - proc = subprocess.Popen( - shell = False, - stdout = subprocess.PIPE, - args = [ - 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 __prepareFormData(self): + (oc1, oc2, oc3, oc4) = self.__getCurrentIP() + self.hdf[self.hdf_prefix + "ip.oc1"] = oc1 + self.hdf[self.hdf_prefix + "ip.oc2"] = oc2 + self.hdf[self.hdf_prefix + "ip.oc3"] = oc3 + self.hdf[self.hdf_prefix + "ip.oc4"] = oc4 -def __setIP(cbox, ip): - proc = subprocess.Popen( - shell = False, - args = [ - cbox.prefs["Programs"]["super"], - cbox.prefs["Programs"]["CryptoBoxRootActions"], - "plugin", - os.path.join(os.path.dirname(__file__), "root_action.py"), - ip]) - proc.communicate() - return proc.returncode == 0 + def __getCurrentIP(self): + import re + import imp + ## load some values from the root_action.py script + root_action_plug = imp.load_source("root_action", os.path.join(self.pluginDir, "root_action.py")) + ## get the current IP of the network interface + proc = subprocess.Popen( + shell = False, + stdout = subprocess.PIPE, + args = [ + 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 diff --git a/pythonrewrite/plugins/partition/lang/en.hdf b/pythonrewrite/plugins/partition/lang/en.hdf index f3dca8c..25f8c82 100644 --- a/pythonrewrite/plugins/partition/lang/en.hdf +++ b/pythonrewrite/plugins/partition/lang/en.hdf @@ -25,6 +25,7 @@ Text { Size = Size (MB) SelectDevice = Choose a disk for partitioning WarningMessage = If you continue, you will destroy all data on the choosen disk. Please be careful! + ProgressInfo = Progress of formatting: } SuccessMessage { diff --git a/pythonrewrite/plugins/partition/partition.py b/pythonrewrite/plugins/partition/partition.py index 2dd3011..b89ea78 100644 --- a/pythonrewrite/plugins/partition/partition.py +++ b/pythonrewrite/plugins/partition/partition.py @@ -2,308 +2,328 @@ import subprocess import os import logging import CryptoBoxTools +import CryptoBoxPlugin -PartTypes = { - "windows" : ["0xC", "vfat"], - "linux" : ["L", "ext3"]} +class partition(CryptoBoxPlugin.CryptoBoxPlugin): -ConfigPartition = { - "size" : 5, # size of configuration partition (if necessary) in MB - "type" : "L", - "fs" : "ext2"} + PartTypes = { + "windows" : ["0xC", "vfat"], + "linux" : ["L", "ext3"]} -logger = logging.getLogger("CryptoBox") + ConfigPartition = { + "size" : 5, # size of configuration partition (if necessary) in MB + "type" : "L", + "fs" : "ext2"} -def doAction(hdf, cbox, **args): - try: - step = args["step"] - del args["step"] - except KeyError: - 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 + def doAction(self, **args): + ## retrieve some values from 'args' - defaults are empty + self.withConfigPartition = self.__isWithConfigPartition(args) + self.device = self.__getSelectedDevice(args) + self.deviceSize = self.__getAvailableDeviceSize(self.device) try: - size = int(args["part%d_size" % i]) - partType = args["part%d_type" % i] - 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 + step = args["step"] + del args["step"] except KeyError: - done = True - return parts + step = "select_device" + ## 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): - """calculate the available size (MB) of the device - also consider a (possible) configuration partition""" - rdev = os.stat(device).st_rdev - minor = os.minor(rdev) - major = os.major(rdev) - for f in file("/proc/partitions"): + def getStatus(self): + return "%s / %s / %s" % (self.device, self.deviceSize, self.withConfigPartition) + + + def __getSelectedDevice(self, args): 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 withConfigPartition: deviceSize -= ConfigPartition["size"] - return deviceSize - except ValueError: - pass - return 0 + device = args["block_device"] + except KeyError: + return None + if not self.__isDeviceValid(device): + return None + if self.__isDeviceBusy(device): + self.hdf["Data.Warning"] = "Plugins.partition.DiskIsBusy" + return None + return device -def __withConfigPartition(args): - try: - if args["create_config_partition"]: - createConfig = True + def __isDeviceValid(self, device): + if not device: + return False + 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: + 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 - except KeyError: - createConfig = False - return createConfig + return createConfig -def __runFDisk(cbox, device, parts, withConfigPartition): - ## check if the device is completely filled (to avoid some empty last blocks) - avail_size = __getAvailableDeviceSize(device, withConfigPartition) - for d in parts: avail_size -= d["size"] - 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 + def __runFDisk(self, parts): + ## check if the device is completely filled (to avoid some empty last blocks) + avail_size = self.deviceSize + for d in parts: avail_size -= d["size"] + 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"], + self.cbox.prefs["Programs"]["super"], + 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 "Failed!" + 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 "Failed!" + 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", os.path.join(os.path.dirname(__file__), "root_action.py"), "format", @@ -311,37 +331,29 @@ def __formatOnePartition(cbox, dev_name, type): type]) (output, error) = proc.communicate() if proc.returncode != 0: - logger.warn("failed to create filesystem on %s: %s" % (dev_name, error)) - sys.exit(1) + self.cbox.log.warn("failed to create filesystem on %s: %s" % (dev_name, error)) + return False else: - sys.exit(0) - else: - time.sleep(1) - (pid, exit_state) = os.waitpid(child_pid, os.WNOHANG) - if ((pid == 0) and (exit_state == 0)) \ - or ((pid == child_pid) and (exit_state == 0)): - return True + return True + + + def __setLabelOfPartition(self, dev_name, label): + proc = subprocess.Popen( + shell = False, + 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: + self.cbox.log.warn("failed to create filesystem on %s: %s" % (dev_name, error)) 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 - diff --git a/pythonrewrite/plugins/partition/root_action.py b/pythonrewrite/plugins/partition/root_action.py index 5601f43..7b360a9 100755 --- a/pythonrewrite/plugins/partition/root_action.py +++ b/pythonrewrite/plugins/partition/root_action.py @@ -26,14 +26,28 @@ def __partitionDevice(device): def __formatPartition(device, type): - proc = subprocess.Popen( - shell = False, - args = [ - MKFS_BIN, - "-t", type, - device]) - proc.communicate() - return proc.returncode == 0 + import time, threading + result = True + def formatting(): + proc = subprocess.Popen( + shell = False, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + 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): diff --git a/pythonrewrite/plugins/partition/set_partitions.cs b/pythonrewrite/plugins/partition/set_partitions.cs index 9491718..4736722 100644 --- a/pythonrewrite/plugins/partition/set_partitions.cs +++ b/pythonrewrite/plugins/partition/set_partitions.cs @@ -35,7 +35,7 @@ - + diff --git a/pythonrewrite/plugins/partition/show_format_progress.cs b/pythonrewrite/plugins/partition/show_format_progress.cs new file mode 100644 index 0000000..715ac93 --- /dev/null +++ b/pythonrewrite/plugins/partition/show_format_progress.cs @@ -0,0 +1,13 @@ + + +

+ +

+

+

+ diff --git a/pythonrewrite/plugins/plugin-interface.txt b/pythonrewrite/plugins/plugin-interface.txt index a801d5f..0c69667 100644 --- a/pythonrewrite/plugins/plugin-interface.txt +++ b/pythonrewrite/plugins/plugin-interface.txt @@ -5,15 +5,20 @@ The following directory structure is required: 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 - 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) - 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 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 "" 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): - - returns a string, that described a state connected to this plugin (e.g. the current date and time (for the "date" plugin) + - function "getStatus": + - 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: