diff --git a/README.md b/README.md index dd25882..85e1da4 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,27 @@ Generate graph: ````shell sudo lsof -n -F | python lsofgraph.py | dot -Tjpg > /tmp/a.jpg + OR +sudo lsof -n -F | python lsofgraph.py | dot -T svg > /tmp/a.svg ```` - or add `unflatten` to the chain for a better layout: ````shell sudo lsof -n -F | python lsofgraph.py | unflatten -l 1 -c 6 | dot -T jpg > /tmp/a.jpg + OR +sudo lsof -n -F | python lsofgraph.py | unflatten -l 1 -c 6 | dot -T svg > /tmp/a.svg ```` +Note: In cases of handling large datasets, you might encounter a "maximum recursion depth exceeded" error. To work around this, you can increase the recursion limit in your Python environment by adding `sys.setrecursionlimit(15000)` in the `lsofgraph.py` script. ![example output](/example.jpg) + +# Install and use on MacOS + +Graphviz contains utilities dot and unflatten +````shell +brew install Graphviz +git clone https://github.com/akme/lsofgraph-python.git +cd lsofgraph-python +lsof -n -F | python lsofgraph.py | unflatten -l 1 -c 6 | dot -T jpg > /tmp/a.jpg && open /tmp/a.jpg +lsof -n -F | python lsofgraph.py | unflatten -l 1 -c 6 | dot -T svg > /tmp/a.jpg && open -a Safari.app '/tmp/a.svg' +```` diff --git a/lsofgraph.py b/lsofgraph.py index c9503c1..b9368ad 100644 --- a/lsofgraph.py +++ b/lsofgraph.py @@ -12,7 +12,7 @@ def parse_lsof(): for line in sys.stdin: if line.startswith("COMMAND"): - print 'did you run lsof without -F?' + print("did you run lsof without -F?") exit(1) tag = line[0] @@ -54,7 +54,7 @@ def find_connections(procs): 'udp': {}, 'pipe': {} } - for pid, proc in procs.iteritems(): + for pid, proc in procs.items(): if 'files' in proc: for _, file in enumerate(proc['files']): @@ -140,7 +140,7 @@ def print_graph(procs, conns): # Parent/child relationships - for pid, proc in procs.iteritems(): + for pid, proc in procs.items(): if 'R' in proc and proc['R'] == "1": color = "grey70" else: @@ -149,12 +149,12 @@ def print_graph(procs, conns): print("\tp%s [ label = \"%s\\n%s %s\" fillcolor=%s ];" % (proc['p'], proc['n'], proc['p'], proc['L'], color)) elif 'p' in proc: - if 'L' in proc: # there could be no L flag if process running, but user was removed. lsof: no pwd entry for UID + if 'L' in proc: # there could be no L flag if process running, but user was removed. lsof: no pwd entry for UID print("\tp%s [ label = \"%s\\n%s %s\" fillcolor=%s ];" % - (proc['p'], proc['c'], proc['p'], proc['L'], color)) + (proc['p'], proc['c'], proc['p'], proc['L'], color)) else: print("\tp%s [ label = \"%s\\n%s %s\" fillcolor=%s ];" % - (proc['p'], proc['c'], proc['p'], "no user", color)) + (proc['p'], proc['c'], proc['p'], "no user", color)) if 'R' in proc and proc['R'] in procs: proc_parent = procs[proc['R']] if proc_parent: @@ -162,7 +162,7 @@ def print_graph(procs, conns): print( "\tp%s -> p%s [ penwidth=2 weight=100 color=grey60 dir=\"none\" ];" % (proc['R'], proc['p'])) - for type, conn in conns.iteritems(): + for type, conn in conns.items(): for id, files in conn.items(): if len(files) == 2: if files[0]['proc'] != files[1]['proc']: @@ -178,6 +178,10 @@ def print_graph(procs, conns): if __name__ == '__main__': - procs = parse_lsof() - conns = find_connections(procs) - print_graph(procs, conns) + sys.setrecursionlimit(15000) # Increase the recursion limit before processing starts + try: + procs = parse_lsof() + conns = find_connections(procs) + print_graph(procs, conns) + except RuntimeError as e: + print("Error: Recursion depth exceeded. Consider increasing the recursion limit.")