pfiles for Linux
Problem
Someone asked if there is a Linux equivalent of the Solaris pfiles tool. pfiles is a Solaris proc utility that reports information of all open files by the process id. Eugene decided to write a similar tool for Linux using SystemTap.
Scripts
This script is part of the standard SystemTap Examples. Get it here http://sourceware.org/systemtap/examples/process/pfiles.stp. Or if you have already downloaded the systemtap tarball, it's in ./testsuite/systemtap.examples/process/pfiles.stp or installed under /usr/share/doc/systemtap-*/examples.
It is based on the example outputs in:
TODO:
report locked open files [completed 14/10/07]
report pathname information [completed 13/10/07]
report socket information [completed 19/01/08]
Output
$ pfiles usage: pfiles pid ... (report open files of each process) $ pfiles `pgrep firefox-bin` | head -24 4118: firefox-bin Current rlimit: 256 file descriptors 0: S_IFCHR mode:0666 dev:0,16 ino:205 uid:500 gid:500 rdev:1,3 O_RDONLY|O_LARGEFILE /dev/null 1: S_IFCHR mode:0666 dev:0,16 ino:205 uid:500 gid:500 rdev:1,3 O_WRONLY|O_LARGEFILE /dev/null 2: S_IFCHR mode:0666 dev:0,16 ino:205 uid:500 gid:500 rdev:1,3 O_WRONLY|O_LARGEFILE /dev/null 3: S_IFSOCK mode:0777 dev:0,5 ino:45113 uid:500 gid:500 rdev:0,0 O_RDWR|O_NONBLOCK FD_CLOEXEC socket:[45113] 4: S_IFIFO mode:0600 dev:0,6 ino:45115 uid:500 gid:500 rdev:0,0 O_RDONLY pipe:[45115] 5: S_IFIFO mode:0600 dev:0,6 ino:45115 uid:500 gid:500 rdev:0,0 O_WRONLY pipe:[45115] 6: S_IFREG mode:0664 dev:253,0 ino:17105675 uid:500 gid:500 rdev:0,0 O_WRONLY advisory write lock set by process 4118 /home/eteo/.mozilla/firefox/abcdefgh.default/.parentlock $ pfiles `pgrep thunderbird-bin` | grep advisory -A1 -B2 6: S_IFREG mode:0664 dev:253,0 ino:15729244 uid:500 gid:500 rdev:0,0 O_WRONLY advisory write lock set by process 3610 /home/eteo/.thunderbird/abcdefgh.default/.parentlock
List all sockets opened by ntpd:
$ pfiles `pgrep ntpd` | grep -i port\: sockname: AF_INET 0.0.0.0 port: 123 sockname: AF_INET6 0000:0000:0000:0000:0000:0000:0000:0000 port: 123 sockname: AF_INET6 0000:0000:0000:0000:0000:0000:0000:0001 port: 123 sockname: AF_INET6 fe80:0000:0000:0000:0218:8bff:febf:XXXX port: 123 sockname: AF_INET 127.0.0.1 port: 123 sockname: AF_INET 192.168.1.X port: 123 sockname: AF_INET6 fe80:0000:0000:0000:0200:00ff:XXXX:0000 port: 123 sockname: AF_INET 192.168.122.X port: 123 sockname: AF_INET 10.64.68.X port: 123
List all AF_UNIX sockets with paths binded by pidgin:
$ pfiles `pgrep pidgin` | grep -i unix\ \/ peername: AF_UNIX /tmp/orbit-eteo/linc-c7b-0-13f16bda309e6 peername: AF_UNIX /var/run/dbus/system_bus_socket peername: AF_UNIX /tmp/.ICE-unix/3105 sockname: AF_UNIX /tmp/orbit-eteo/linc-6a1b-0-3c1dac62998f6 sockname: AF_UNIX /tmp/orbit-eteo/linc-6a1b-0-3c1dac62998f6
Compare pidgin’s output with the following. Now I know why nothing happens when I try to press ctrl+space in my pidgin chat window. Something is broken.
$ pfiles `pgrep firefox-bin` | grep -i unix\ \/ | grep scim peername: AF_UNIX /tmp/scim-bridge-0.3.0.socket-500@localhost:0.0
List opened files that are locked:
$ pfiles 2676 | grep advisory -A1 -B2 3: S_IFREG mode:0644 dev:253,0 ino:459459 uid:0 gid:0 rdev:0,0 O_RDWR FD_CLOEXEC advisory write lock set by process 2675 /var/run/crond.pid
bind() was called with INADDR_ANY as its IP address:
$ pfiles `pgrep dnsmasq` | tail -4 11: S_IFSOCK mode:0777 dev:0,5 ino:8996 uid:99 gid:40 rdev:0,0 O_RDWR|O_NONBLOCK socket:[8996] sockname: AF_INET 0.0.0.0 port: 32771
Lessons
You can write very useful systems tools that are not available in Linux with SystemTap. pfiles and plimit are excellent examples.
Reference
The GNU C Library - Descriptor Flags
- Macro int FD_CLOEXEC
- This flag specifies that the file descriptor should be closed when an exec function is invoked; see Executing a File. When a file descriptor is allocated (as with open or dup), this bit is initially cleared on the new file descriptor, meaning that descriptor will survive into the new program after exec .
- Macro int FD_CLOEXEC
- F_GETLK
- If you want to only check to see if there is a lock, but don't want to set one, you can use this command. It looks through all the file locks until it finds one that conflicts with the lock you specified in the struct flock. It then copies the conflicting lock's information into the struct and returns it to you. If it can't find a conflicting lock, fcntl() returns the struct as you passed it, except it sets the l_type field to F_UNLCK.
- F_GETLK
locktst.c test - Andrew's junkcode rocks!