Skip to content

Instantly share code, notes, and snippets.

@kohenkatz
Created June 3, 2014 02:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kohenkatz/28117658d674b9c785f9 to your computer and use it in GitHub Desktop.
Save kohenkatz/28117658d674b9c785f9 to your computer and use it in GitHub Desktop.
lsof utility wrapper copied from http://www.remix.net/blog/?p=130
#!/usr/bin/python
from subprocess import Popen, PIPE
import re
class lsof():
"""
lsof wrapper class
An automated wrapper around lsof output that yields
an array of processes with their file handle information
in the form of:
results = [
{
info: {
'none': '',
'user_id': '501',
'process_id': '22665',
'process_group_id': '20',
'parent_pid': '232',
'login_name': 'nar',
'command_name': 'mdworker'
},
files: [
...
]
},
...
"""
LSOF_BIN='/usr/sbin/lsof'
flagRegex = re.compile("\s+(?P<flag>[a-zA-Z])\s+(?P<desc>.*)$")
flag_cache = {'': 'none'}
def __init__(self):
"""
For initialization, we query lsof using the '-Fh?' flag
to automatically generate a list of possible key names
so that later on when we're parsing records we can substitute
them in the final dict.
When using the -F option, the key names are only provided as
single characters, which aren't terribly useful if you don't
know them by heart.
"""
cmd = "%s -F?" % (self.LSOF_BIN)
p = Popen( [ self.LSOF_BIN, "-F?" ] , stdout=PIPE, stderr=PIPE, close_fds=True )
for line in p.stderr.readlines()[1:]:
m = self.flagRegex.match(line)
if m is not None:
flag = m.group('flag')
desc = m.group('desc').lower()
for s in (':', ' as', ' ('):
if desc.find(s) > -1:
desc = desc[0:desc.find(s)]
break
self.flag_cache[m.group('flag')] = re.sub('[/ ,\t_]+', '_', desc)
def run(self):
"""
run lsof and parse the results into a tmp array that gets passed back to the
caller.
"""
tmp = []
cmd = "%s -PnF0" % (self.LSOF_BIN)
p = Popen(cmd.split(' '), stdout=PIPE, close_fds=True)
for line in p.stdout.xreadlines():
r = dict( [ ( self.flag_cache[x[0:1]], x[1:] ) for x in line.rstrip('\n').split('\0') ] )
if r.has_key('command_name'):
tmp.append( { 'info': r, 'files': [] } )
else:
tmp[-1]['files'].append(r)
return tmp
if __name__ == '__main__':
import pprint
l = lsof()
for r in l.run():
info = r['info']
files = r['files']
print "PID(%s) %s" % (info['process_id'], info['command_name'])
for f in files:
for k in f.keys():
print "\t%-20s -> %s" % ( k, f[k] )
@Fclem
Copy link

Fclem commented Apr 19, 2017

Now fixed, tested and working on linux, see the related fork (and the diff)

Changes :

  • fixed indentation
  • PEP8 compliance
  • python3 compatibility using __future__ import
  • line 06 : using CamelCase for class name, and new style class
  • line 34 : fixed lsof path, using dynamic path resolution from distutils.spawn.find_executable
  • line 35 : fixed broken regexp
  • line 50 : removed useless cmd variable
  • line 61 : replaced flag_cache dict key by previously unused variable flag
  • line 63 : renamed r to r2 in run() for clarity
  • line 70 : removed useless parenthesis
  • line 74 : replaced has_key() by in operator
  • line 81 : removed useless pprint import
  • line 89 : removed useless .keys() for f

Thanks to the original author Nathan Ramella, see the original post from Nov. 2012 at Internet Archive (original page is defunct)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment