diff --git a/usb/usb b/usb/usb index f74f0e44..c7bc9850 100755 --- a/usb/usb +++ b/usb/usb @@ -1,12 +1,13 @@ #!/usr/bin/env python3 # -# Copyright (C) 2015 James Murphy -# Licensed under the terms of the GNU GPL v2 only. -# -# i3blocks blocklet script to output connected usb storage device info. +# Copyright (C) 2015 James Murphy +# Licensed under the terms of the GNU GPL v2 only. +# +# i3blocks blocklet script to output connected usb storage device info. import os + def _default(name, default='', arg_type=str): val = default if name in os.environ: @@ -17,10 +18,11 @@ def _default(name, default='', arg_type=str): # BEGIN CONFIG # Most of these can be specified as command line options, run with --help for # more information. -# You may edit any of the following entries. DO NOT delete any of them, else +# You may edit any of the following entries. DO NOT delete any of them, else # the main script will have unpredictable behavior. ############################################################################### + # Color options, can be a color name or #RRGGBB INFO_TEXT_COLOR = _default("INFO_TEXT_COLOR", "white") MOUNTED_COLOR = _default("MOUNTED_COLOR", "green") @@ -33,7 +35,7 @@ PARTITIONLESS_COLOR = _default("PARTITIONLESS_COLOR", "red") PARTITIONLESS_TEXT = _default("PARTITIONLESS_TEXT", "no partitions") SEPARATOR = _default("SEPARATOR", " | ") -# Indicate whether an encrypted partition is locked/unlocked, "" is allowed. +# Indicate whether an encrypted partition is locked/unlocked, "" is allowed. LOCKED_INDICATOR = _default("LOCKED_INDICATOR", "\uf023 ") UNLOCKED_INDICATOR = _default("UNLOCKED_INDICATOR", "\uf09c ") @@ -51,11 +53,11 @@ TRUNCATE_FS_LABELS = _default("TRUNCASE_FS_LABELS", None) IGNORE_LIST = _default("IGNORE_LIST", "[]") if IGNORE_LIST: import ast - IGNORE_LIST = list(map(lambda p: - p if p.startswith("/") - else "/dev/{}".format(p), - ast.literal_eval(IGNORE_LIST) - )) + IGNORE_LIST = list(map(lambda p: + p if p.startswith("/") + else "/dev/{}".format(p), + ast.literal_eval(IGNORE_LIST) + )) # Edit this function to ignore certain devices (e.g. those that are always @@ -64,8 +66,8 @@ if IGNORE_LIST: # udevadm info --query=propery --name=$path def ignore(path, udev_attributes_dict): # E.g. how to ignore devices whose device name begins with /dev/sda - #if udev_attributes_dict["DEVNAME"].startswith("/dev/sda"): - # return True + # if udev_attributes_dict["DEVNAME"].startswith("/dev/sda"): + # return True return False # Edit this function to ignore devices before the udev attributes are @@ -75,12 +77,12 @@ def fastIgnore(path): return True # E.g. how to to ignore devices whose path begins with /dev/sda - #if path.startswith("/dev/sda"): - # return True + # if path.startswith("/dev/sda"): + # return True # E.g. how to ignore a fixed set of paths - #if path in [ "/dev/path1", "/dev/path2", "/dev/path3" ]: - # return True + # if path in [ "/dev/path1", "/dev/path2", "/dev/path3" ]: + # return True return False ############################################################################### @@ -94,30 +96,37 @@ import argparse def pangoEscape(text): return text.replace("&", "&").replace("<", "<").replace(">", ">") + def getLeafDevicePaths(): lines = check_output(['lsblk', '-spndo', 'NAME'], universal_newlines=True) lines = lines.split("\n") lines = filter(None, lines) return lines + def getKernelName(path): return check_output(['lsblk', '-ndso', 'KNAME', path], - universal_newlines=True).rstrip("\n") + universal_newlines=True).rstrip("\n") + def getDeviceType(path): return check_output(['lsblk', '-no', 'TYPE', path], - universal_newlines=True).strip() + universal_newlines=True).strip() + def getFSType(path): global attributeMaps return attributeMaps[path].get("ID_FS_TYPE") + def isLUKSPartition(path): return getFSType(path) == "crypto_LUKS" + def isSwapPartition(path): return getFSType(path) == "swap" + def getFSLabel(path): global attributeMaps label = attributeMaps[path].get("ID_FS_LABEL_ENC", "") @@ -130,48 +139,56 @@ def getFSLabel(path): label = label[TRUNCATE_FS_LABELS:] return label + def getFSOptions(path): lines = check_output(['findmnt', '-no', 'FS-OPTIONS', path], - universal_newlines=True).strip() + universal_newlines=True).strip() lines = lines.split(",") return lines + def isReadOnly(path): return "ro" in getFSOptions(path) + def isExtendedPartitionMarker(path): global attributeMaps MARKERS = ["0xf", "0x5"] return attributeMaps[path].get("ID_PART_ENTRY_TYPE") in MARKERS + def getMountPoint(path): return check_output(['lsblk', '-ndo', 'MOUNTPOINT', path], - universal_newlines=True).rstrip("\n") + universal_newlines=True).rstrip("\n") + def getSpaceAvailable(path): lines = check_output(['df', '-h', '--output=avail', path], - universal_newlines=True) + universal_newlines=True) lines = lines.split("\n") if len(lines) != 3: return "" else: return lines[1].strip() + def getLockedCryptOutput(path): form = "[{}{}]" kname = pangoEscape(getKernelName(path)) output = form.format(LOCKED_COLOR, LOCKED_INDICATOR, kname) return output + def getParentKernelName(path): lines = check_output(['lsblk', '-nso', 'KNAME', path], - universal_newlines=True) + universal_newlines=True) lines = lines.split("\n") if len(lines) > 2: return lines[1].rstrip("\n") else: return "" + def getUnlockedCryptOutput(path): mountPoint = getMountPoint(path) if mountPoint: @@ -186,9 +203,10 @@ def getUnlockedCryptOutput(path): spaceAvail = "" kernelName = pangoEscape(getKernelName(path)) parentKernelName = pangoEscape(getParentKernelName(path)) - + block = "[{}{}:{}]" - block = block.format(color, UNLOCKED_INDICATOR, parentKernelName, kernelName) + block = block.format(color, UNLOCKED_INDICATOR, + parentKernelName, kernelName) label = pangoEscape(getFSLabel(path)) if label: @@ -197,15 +215,17 @@ def getUnlockedCryptOutput(path): items = [block, label, mountPoint, spaceAvail] return " ".join(filter(None, items)) + def getSwapOutput(path): return "" -def getUnencryptedPartitionOutput(path): + +def getUnencryptedPartitionOutput(path): mountPoint = getMountPoint(path) if mountPoint: color = MOUNTED_COLOR if isReadOnly(path): - spaceAvail = READONLY_INDICATOR + spaceAvail = READONLY_INDICATOR else: spaceAvail = pangoEscape(getSpaceAvailable(path)) mountPoint = "{}:".format(pangoEscape(mountPoint)) @@ -224,11 +244,13 @@ def getUnencryptedPartitionOutput(path): items = [block, label, mountPoint, spaceAvail] return " ".join(filter(None, items)) + def getDiskWithNoPartitionsOutput(path): form = "[{}] {}" kernelName = pangoEscape(getKernelName(path)) return form.format(PARTITIONLESS_COLOR, kernelName, PARTITIONLESS_TEXT) + def getOutput(path): if isSwapPartition(path): return getSwapOutput(path) @@ -244,14 +266,15 @@ def getOutput(path): return getDiskWithNoPartitionsOutput(path) elif t == "crypt": return getUnlockedCryptOutput(path) - elif t == "rom" : + elif t == "rom": return "" + def makeAttributeMap(path): attributeMap = {} lines = check_output( - ['udevadm','info','--query=property','--name={}'.format(path)], - universal_newlines=True) + ['udevadm', 'info', '--query=property', '--name={}'.format(path)], + universal_newlines=True) lines = lines.split("\n") for line in lines: if line: @@ -259,8 +282,10 @@ def makeAttributeMap(path): attributeMap[key] = val return attributeMap + def getAttributeMaps(paths): - return {path : makeAttributeMap(path) for path in paths} + return {path: makeAttributeMap(path) for path in paths} + def parseArguments(): parser = argparse.ArgumentParser(prog="usb.py", @@ -308,53 +333,57 @@ def parseArguments(): "If path doesn't begin with / then it is assumed to be in /dev/") args = parser.parse_args() setParsedArgs(args) - + + def setParsedArgs(args): - if args.info_text_color != None: + if args.info_text_color is not None: global INFO_TEXT_COLOR INFO_TEXT_COLOR = args.info_text_color[0] - if args.mounted_color != None: + if args.mounted_color is not None: global MOUNTED_COLOR MOUNTED_COLOR = args.mounted_color[0] - if args.plugged_color != None: + if args.plugged_color is not None: global PLUGGED_COLOR PLUGGED_COLOR = args.plugged_color[0] - if args.locked_color != None: + if args.locked_color is not None: global LOCKED_COLOR LOCKED_COLOR = args.locked_color[0] - if args.unlocked_not_mounted_color != None: + if args.unlocked_not_mounted_color is not None: global UNLOCKED_NOT_MOUNTED_COLOR UNLOCKED_NOT_MOUNTED_COLOR = args.unlocked_not_mounted_color[0] - if args.partitionless_color != None: + if args.partitionless_color is not None: global PARTITIONLESS_COLOR PARTITIONLESS_COLOR = args.partitionless_color[0] - if args.partitionless_text != None: + if args.partitionless_text is not None: global PARTITIONLESS_TEXT PARTITIONLESS_TEXT = args.partitionless_text[0] - if args.separator != None: + if args.separator is not None: global SEPARATOR SEPARATOR = args.separator[0] - if args.locked_indicator != None: + if args.locked_indicator is not None: global LOCKED_INDICATOR LOCKED_INDICATOR = args.locked_indicator[0] - if args.unlocked_indicator != None: + if args.unlocked_indicator is not None: global UNLOCKED_INDICATOR UNLOCKED_INDICATOR = args.unlocked_indicator[0] - if args.readonly_indicator != None: + if args.readonly_indicator is not None: global READONLY_INDICATOR READONLY_INDICATOR = args.readonly_indicator[0] - if args.truncate_fs_labels != None: + if args.truncate_fs_labels is not None: global TRUNCATE_FS_LABELS TRUNCATE_FS_LABELS = args.truncate_fs_labels[0] - if args.ignore != None: - args.ignore = list(map(lambda p: - p if p.startswith("/") else "/dev/{}".format(p), args.ignore)) + if args.ignore is not None: + args.ignore = list(map(lambda p: + p if p.startswith("/") else "/dev/{}".format(p), + args.ignore)) global fastIgnore oldFastIgnore = fastIgnore + def newFastIgnore(path): return oldFastIgnore(path) or path in args.ignore fastIgnore = newFastIgnore + parseArguments() leaves = getLeafDevicePaths() leaves = [path for path in leaves if not fastIgnore(path)]