Last active
September 12, 2018 13:08
-
-
Save jn0/39b31c77ce6f6ac4831279ac38057a3e to your computer and use it in GitHub Desktop.
Handy wrapper to [sys/proc] filesystem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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