Skip to content

Instantly share code, notes, and snippets.

@jn0
Last active September 12, 2018 13:08
Show Gist options
  • Save jn0/39b31c77ce6f6ac4831279ac38057a3e to your computer and use it in GitHub Desktop.
Save jn0/39b31c77ce6f6ac4831279ac38057a3e to your computer and use it in GitHub Desktop.
Handy wrapper to [sys/proc] filesystem
#!/usr/bin/python
import os
import errno
AUTO_EXPAND_USER = True
def RootFS(root='/'): return FS(root)
def SysFS(root='/sys'): return FS(root)
def ProcFS(root='/proc'): return FS(root)
def MyFS(root='~'): return FS(root)
readable = lambda x: os.access(x, os.R_OK)
def read_file(path, size=8192):
if readable(path):
try:
with open(path) as f: # this may hang on 2nd read(2)...
return os.read(f.fileno(), size) # *single* read(2) op!
except OSError as e:
if e.errno in (errno.EIO, errno.ENODATA, errno.ENXIO, errno.EPERM,
errno.EINVAL, errno.ENOTSUP, errno.ENODEV):
return None # ignore some errors
raise
return None
def resolve_link(path):
link = os.readlink(path)
if not os.path.isabs(link):
link = os.path.join(os.path.dirname(path), link)
return os.path.realpath(link)
class FS(object):
EXISTS = 0
IS_DIR = 1
IS_LINK = 2
IS_MOUNT = 3
IS_FILE = 4
def __init__(self, path):
self._cache = {}
if path.startswith('~') and AUTO_EXPAND_USER:
path = os.path.expanduser(path)
self.path = path
self.rpath = os.path.realpath(self.path)
self.content = None
self.flags = set()
if os.path.exists(self.path): self.flags |= { FS.EXISTS }
if os.path.isdir(self.path): self.flags |= { FS.IS_DIR }
if os.path.islink(self.path): self.flags |= { FS.IS_LINK }
if os.path.ismount(self.path): self.flags |= { FS.IS_MOUNT }
if os.path.isfile(self.path): self.flags |= { FS.IS_FILE }
if FS.EXISTS in self.flags:
if FS.IS_LINK in self.flags:
self.rpath = resolve_link(self.path)
if FS.IS_FILE in self.flags:
self.content = read_file(self.rpath)
elif FS.IS_DIR in self.flags:
self.content = sorted(os.listdir(self.path))
@property
def exists(self): return FS.EXISTS in self.flags
@property
def isdir(self): return FS.IS_DIR in self.flags
@property
def islink(self): return FS.IS_LINK in self.flags
@property
def ismount(self): return FS.IS_MOUNT in self.flags
@property
def isfile(self): return FS.IS_FILE in self.flags
@property
def isnone(self): return self.flags == set()
@property
def _suffix(self):
return ''.join((
'/' if self.isdir else '',
'>' if self.islink else '',
'!' if self.ismount else '',
'=' if self.isfile else '',
'?' if self.isnone else '',
))
def __repr__(self):
return self.path
def __str__(self):
return '{path}{suffix}{rpath}'.format(
path=self.path,
suffix=self._suffix,
rpath=(' ' + self.rpath) if self.islink else '',
)
def __call__(self, *av, **kw):
if not av:
return self.content
if callable(av[0]):
return av[0](self.content)
raise NotImplementedError(av)
def __getitem__(self, name):
if type(name) is int: # iterator call?
return self.content[name]
path = name if os.path.isabs(name) else os.path.join(self.path, name)
if path not in self._cache:
if not os.path.exists(path):
raise KeyError(name)
self._cache[path] = FS(path)
return self._cache[path]
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
#end class FS
def print_seen_tree(ent):
print(ent)
for e in ent._cache:
print_seen_tree(ent._cache[e])
if __name__ == '__main__':
root = FS('/')
print root.etc.passwd, root.etc.passwd()
print root.proc.mounts()
sys = SysFS()
sys_class = sys['class']
print sys_class.block, len(sys_class.block()), '; '.join(sys_class.block())
print sys_class.block.sda1, sys['class'].block.sda1()
print sys_class.block.sda1.partition, sys_class.block.sda1.partition(int),
print repr(sys['class'].block.sda1.partition)
print sys.dev.block['8:5'], sys.dev.block['8:5']()
print sys.dev, 'block:', hasattr(sys.dev, 'block')
print sys.dev, 'no-such-entry:', hasattr(sys.dev, 'no-such-entry')
print "'8:5' in", sys.dev.block, ':', '8:5' in sys.dev.block
print "'no-such-entry' in", sys.dev.block, ':', 'no-such-entry' in sys.dev.block
for b in sys.dev.block:
print sys.dev.block, b, sys.dev.block[b]
print_seen_tree(sys)
# EOF #
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment