Skip to content

Instantly share code, notes, and snippets.

@lhchavez
Created February 11, 2016 06:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lhchavez/b90b92c5ded9081956bc to your computer and use it in GitHub Desktop.
Save lhchavez/b90b92c5ded9081956bc to your computer and use it in GitHub Desktop.
strace wrapper to display the read/written files of a process tree
#!/usr/bin/python
import argparse
import collections
import os
import os.path
import re
import subprocess
import sys
import threading
def readpipe(summary, directories):
forkre = re.compile(r'(\d+) .*fork.* =\s+(.*)')
syscallre = re.compile(r'(\d+) ([a-z]+)\((.*)\)\s+=\s+(.*)')
cwd = collections.defaultdict(lambda: os.getcwd())
reads = collections.defaultdict(set)
writes = collections.defaultdict(set)
fds = collections.defaultdict(dict)
with open('.pipe', 'r') as fifo:
for line in fifo:
m = forkre.match(line)
if m != None:
pid, retval = m.groups()
cwd[int(retval)] = cwd[pid]
continue
m = syscallre.match(line)
if not m: continue
pid, syscall, args, retval = m.groups()
pid = int(pid)
if retval.startswith('-1'): continue
if syscall == 'chdir':
cwd[pid] = os.path.abspath(os.path.join(cwd[pid], args.strip('"')))
elif syscall == 'open':
filename, flags = args.split(', ')[:2]
filename = os.path.abspath(os.path.join(cwd[pid], filename.strip('"')))
fds[pid][int(retval)] = filename
if 'O_CREAT' in flags:
writes[pid].add(filename)
else:
reads[pid].add(filename)
elif syscall == 'creat':
filename = args.split(', ')[0].strip('"')
fds[pid][int(retval)] = filename
writes[pid].add(filename)
elif syscall == 'close':
if int(args) in fds[pid]:
del fds[pid][int(args)]
elif syscall == 'openat':
fd, filename, flags = args.split(', ')[:3]
if fd == 'AT_FDCWD':
filename = os.path.abspath(os.path.join(cwd[pid], filename.strip('"')))
else:
filename = os.path.abspath(os.path.join(fds[pid][int(fd)],
filename.strip('"')))
fds[pid][int(retval)] = filename
if 'O_CREAT' in flags:
writes[pid].add(filename)
else:
reads[pid].add(filename)
if directories:
directories = map(os.path.abspath, directories)
if summary:
sreads = set()
swrites = set()
for pid in cwd.keys():
sreads.update(reads[pid])
swrites.update(writes[pid])
print 'reads:'
for r in sreads:
if directories and not any([r.startswith(d) for d in directories]):
continue
print '\t%s' % r
print 'writes:'
for w in swrites:
if directories and not any([w.startswith(d) for d in directories]):
continue
print '\t%s' % w
else:
for pid in cwd.keys():
print pid
print '\treads:'
for r in reads[pid]:
if directories and not any([r.startswith(d) for d in directories]):
continue
print '\t\t%s' % r
print '\twrites:'
for w in writes[pid]:
if directories and not any([w.startswith(d) for d in directories]):
continue
print '\t\t%s' % w
def main():
parser = argparse.ArgumentParser(
description='Inspect all opened files from a process tree')
parser.add_argument('--include', metavar='dir', type=str, dest='directories',
nargs='+', help='Only include files under the specified directories')
parser.add_argument('--summary', default=False, action='store_true',
help='Print a summary of all files read/written to')
parser.add_argument('args', metavar='arg', type=str, nargs='+',
help='The command to be executed')
args = parser.parse_args()
try:
os.mkfifo('.pipe')
thread = threading.Thread(target=readpipe,
args=(args.summary, args.directories,))
thread.start()
subprocess.check_call(['/usr/bin/strace', '-f', '-e',
'trace=fork,vfork,creat,open,chdir,openat,close',
'-o', '.pipe'] + args.args)
finally:
os.unlink('.pipe')
if __name__ == '__main__':
sys.exit(main())
# vim: set expandtab:ts=2:sw=2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment