import logging import os import re logger = logging.getLogger("CryptoBox") def getAvailablePartitions(): "retrieve a list of all available containers" ret_list = [] try: "the following reads all lines of /proc/partitions and adds the mentioned devices" fpart = open("/proc/partitions", "r") try: line = fpart.readline() while line: p_details = line.split() if (len(p_details) == 4): "the following code prevents double entries like /dev/hda and /dev/hda1" (p_major, p_minor, p_size, p_device) = p_details ## ignore lines with: invalid minor/major or extend partitions (size=1) if re.search('^[0-9]*$', p_major) and re.search('^[0-9]*$', p_minor) and (p_size != "1"): p_parent = re.sub('[1-9]?[0-9]$', '', p_device) if p_parent == p_device: if [e for e in ret_list if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]: "major partition - its children are already in the list" pass else: "major partition - but there are no children for now" ret_list.append(p_device) else: "minor partition - remove parent if necessary" if p_parent in ret_list: ret_list.remove(p_parent) ret_list.append(p_device) line = fpart.readline() finally: fpart.close() return map(getAbsoluteDeviceName, ret_list) except IOError: logger.warning("Could not read /proc/partitions") return [] def getAbsoluteDeviceName(shortname): """ returns the absolute file name of a device (e.g.: "hda1" -> "/dev/hda1") this does also work for device mapper devices if the result is non-unique, one arbitrary value is returned""" if re.search('^/', shortname): return shortname default = os.path.join("/dev", shortname) if os.path.exists(default): return default result = findMajorMinorOfDevice(shortname) "if no valid major/minor was found -> exit" if not result: return default (major, minor) = result "for device-mapper devices (major == 254) ..." if major == 254: result = findMajorMinorDeviceName("/dev/mapper", major, minor) if result: return result[0] "now check all files in /dev" result = findMajorMinorDeviceName("/dev", major, minor) if result: return result[0] return default def findMajorMinorOfDevice(device): "return the major/minor numbers of a block device" if re.match("/", device) or not os.path.exists(os.path.join(os.path.sep,"sys","block",device)): ## maybe it is an absolute device name if not os.path.exists(device): return None ## okay - it seems to to a device node rdev = os.stat(device).st_rdev return (os.major(rdev), os.minor(rdev)) blockdev_info_file = os.path.join(os.path.join(os.path.sep,"sys","block", device), "dev") try: f_blockdev_info = open(blockdev_info_file, "r") blockdev_info = f_blockdev_info.read() f_blockdev_info.close() (str_major, str_minor) = blockdev_info.split(":") "numeric conversion" try: major = int(str_major) minor = int(str_minor) return (major, minor) except ValueError: "unknown device numbers -> stop guessing" return None except IOError: pass return None def findMajorMinorDeviceName(dir, major, minor): "returns the names of devices with the specified major and minor number" collected = [] try: subdirs = [os.path.join(dir, e) for e in os.listdir(dir) if (not os.path.islink(os.path.join(dir, e))) and os.path.isdir(os.path.join(dir, e))] "do a recursive call to parse the directory tree" for dirs in subdirs: collected.extend(findMajorMinorDeviceName(dirs, major, minor)) "filter all device inodes in this directory" collected.extend([os.path.realpath(os.path.join(dir, e)) for e in os.listdir(dir) if (os.major(os.stat(os.path.join(dir, e)).st_rdev) == major) and (os.minor(os.stat(os.path.join(dir, e)).st_rdev) == minor)]) ## remove double entries result = [] for e in collected: if e not in result: result.append(e) return result except OSError: return [] def getParentBlockDevices(): devs = [] for line in file("/proc/partitions"): p_details = line.split() ## we expect four values - otherwise continue with next iteration if len(p_details) != 4: continue (p_major, p_minor, p_size, p_device) = p_details ## we expect numeric values in the first two columns if re.search(u'\D',p_major) or re.search(u'\D',p_minor): continue ## now let us check, if it is a (parent) block device or a partition if not os.path.isdir(os.path.join(os.path.sep, "sys", "block", p_device)): continue devs.append(p_device) return map(getAbsoluteDeviceName, devs) def isPartOfBlockDevice(parent, subdevice): """check if the given block device is a parent of 'subdevice' e.g. for checking if a partition belongs to a block device""" try: (par_major, par_minor) = findMajorMinorOfDevice(parent) (sub_major, sub_minor) = findMajorMinorOfDevice(subdevice) except TypeError: ## at least one of these devices did not return a valid major/minor combination return False ## search the entry below '/sys/block' belonging to the parent root = os.path.join(os.path.sep, 'sys', 'block') for bldev in os.listdir(root): blpath = os.path.join(root, bldev, 'dev') if os.access(blpath, os.R_OK): try: if (str(par_major), str(par_minor)) == tuple([e for e in file(blpath)][0].strip().split(":",1)): parent_path = os.path.join(root, bldev) break except IndexError, OSError: pass else: ## no block device with this major/minor combination found below '/sys/block' return False for subbldev in os.listdir(parent_path): subblpath = os.path.join(parent_path, subbldev, "dev") if os.access(subblpath, os.R_OK): try: if (str(sub_major), str(sub_minor)) == tuple([e for e in file(subblpath)][0].strip().split(":",1)): ## the name of the subdevice node is not important - we found it! return True except IndexError, OSError: pass return False def getBlockDeviceSize(device): if not device: return -1 try: rdev = os.stat(device).st_rdev except OSError: return -1 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): return int(elements[2])/1024 except ValueError: pass return -1 def getBlockDeviceSizeHumanly(device): size = getBlockDeviceSize(device) if size > 5120: return "%sGB" % size/1024 else: return "%sMB" % size