Getting current file position from a running process

That was my question in the local linux mailinglist. I received some interesting responses, but while I was writing my own solution (a kernel module that dumps the struct *file->pos) I found that this is already implemented!

Just look at the /proc/<pid>/fdinfo/ files… Here is an example:
# cat /proc/1/fdinfo/1
pos: 0
flags: 02

That special file does exactly what I was doing: getting the struct task_struct for a PID, then getting its struct files_struct, and then the pos of the struct file. The code is in the linux kernel, in the function proc_fd_info inside fs/proc/base.c.

And here is a python script that helps a lot:
#!/usr/bin/env python
# Copyright(C) 2009 Aldrin Martoq
# Licensed under GPL v2 http://www.gnu.org/licenses/gpl-2.0.html
# version 20090206-01

import sys, os

skip = 'socket pipe /dev inotify anon_inode'.split()
cols = 'pid cmdline fd pos size % path'.split()
fmts = '%5s %-15.15s %3s %12s %12s %5s %s'.split()
p1 = '/proc/%s/fdinfo/'
p2 = '/proc/%s/fdinfo/%s'
p3 = '/proc/%s/fd/%s'
p4 = '/proc/%s/cmdline'

for i in range(len(fmts)):
print fmts[i] % cols[i],
print

for pid in sys.argv[1:]:
for fd in os.listdir(p1 % pid):
try:
d = dict(tuple(map(str.strip, l.split(':'))) \
for l in open(p2 % (pid, fd)))
d['path'] = os.readlink(p3 % (pid,fd))
# skip irrelevant fd's...
for p in skip:
if d['path'].startswith(p): break
else:
d['fd'] = fd
d['pid'] = pid
d['cmdline'] = open(p4 % pid).readline().strip()
try: d['size'] = str(os.stat(d['path'])[6])
except: d['size'] = '-'
try: d['%'] = '%5.1f' % (100.0 * int(d['pos']) / int(d['size']))
except: d['%'] = '-'
for i in range(len(fmts)):
print fmts[i] % d[cols[i]].replace('\0', ' '),
print
except Exception, e: print 'FIXME: ' + e

Sample usage:

amartoq@videopodcast:~$ sudo ./fdpos.py $(pgrep ^postgres)
pid cmdline fd pos size % path
13876 /usr/lib/postgr 1 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13876 /usr/lib/postgr 2 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13891 postgres: write 1 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13891 postgres: write 2 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13892 postgres: wal w 1 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13892 postgres: wal w 2 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13893 postgres: autov 1 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13893 postgres: autov 2 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13894 postgres: stats 1 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
13894 postgres: stats 2 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
15921 postgres: amart 1 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
15921 postgres: amart 2 51519 51519 100.0 /var/log/postgresql/postgresql-8.3-main.log
15921 postgres: amart 3 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2684
15921 postgres: amart 6 57344 57344 100.0 /var/lib/postgresql/8.3/main/base/16473/2663
15921 postgres: amart 7 303104 311296 97.4 /var/lib/postgresql/8.3/main/base/16473/1249
15921 postgres: amart 10 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2693
15921 postgres: amart 11 8192 65536 12.5 /var/lib/postgresql/8.3/main/base/16473/2618
15921 postgres: amart 12 65536 90112 72.7 /var/lib/postgresql/8.3/main/base/16473/2689
15921 postgres: amart 13 16384 106496 15.4 /var/lib/postgresql/8.3/main/base/16473/2617
15921 postgres: amart 14 16384 32768 50.0 /var/lib/postgresql/8.3/main/base/16473/2688
15921 postgres: amart 15 49152 57344 85.7 /var/lib/postgresql/8.3/main/base/16473/2690
15921 postgres: amart 16 65536 409600 16.0 /var/lib/postgresql/8.3/main/base/16473/1255
15921 postgres: amart 17 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2703
15921 postgres: amart 18 16384 57344 28.6 /var/lib/postgresql/8.3/main/base/16473/1247
15921 postgres: amart 19 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2661
15921 postgres: amart 20 8192 16384 50.0 /var/lib/postgresql/8.3/main/base/16473/2605
15921 postgres: amart 21 147456 327680 45.0 /var/lib/postgresql/8.3/main/base/16473/2691
15921 postgres: amart 22 16384 32768 50.0 /var/lib/postgresql/8.3/main/base/16473/2686
15921 postgres: amart 23 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2616
15921 postgres: amart 24 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2654
15921 postgres: amart 25 49152 49152 100.0 /var/lib/postgresql/8.3/main/base/16473/1259
15921 postgres: amart 26 8192 8192 100.0 /var/lib/postgresql/8.3/main/base/16473/2601
15921 postgres: amart 27 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2678
15921 postgres: amart 28 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2662
15921 postgres: amart 29 8192 8192 100.0 /var/lib/postgresql/8.3/main/global/1260
15921 postgres: amart 30 16384 16384 100.0 /var/lib/postgresql/8.3/main/global/2676
15921 postgres: amart 31 16384 16384 100.0 /var/lib/postgresql/8.3/main/global/2677
15921 postgres: amart 32 8192 8192 100.0 /var/lib/postgresql/8.3/main/base/16473/2615
15921 postgres: amart 33 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2685
15921 postgres: amart 34 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2696
15921 postgres: amart 35 8192 90112 9.1 /var/lib/postgresql/8.3/main/base/16473/2619
15921 postgres: amart 36 49152 57344 85.7 /var/lib/postgresql/8.3/main/base/16473/2704
15921 postgres: amart 37 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2650
15921 postgres: amart 38 8192 8192 100.0 /var/lib/postgresql/8.3/main/base/16473/2600
15921 postgres: amart 39 73728 73728 100.0 /var/lib/postgresql/8.3/main/base/16473/2659
15921 postgres: amart 40 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/2656
15921 postgres: amart 41 8192 8192 100.0 /var/lib/postgresql/8.3/main/base/16473/2604
15921 postgres: amart 42 8192 8192 100.0 /var/lib/postgresql/8.3/main/base/16473/16666
15921 postgres: amart 43 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/16675
15921 postgres: amart 44 16384 16384 100.0 /var/lib/postgresql/8.3/main/base/16473/16677

Updated 2009-02-06: Thanks to Daniel Serpell for fixing my bugs.

0 Responses to “Getting current file position from a running process”


  • No Comments

Leave a Reply