1)查看对某个文件的使用情况
-------------------------------------------------------
root@troy:/# lsof -w /etc/passwd
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python 2340 troy 10r REG 8,1 1804 2886346 /etc/passwd
-------------------------------------------------------
注:-w参数表示不打印警告信息.
lsof程序会打开/proc/PID/fd/目录找到对映的文件句柄,再通过stat系统调用得到文件的详细信息.
同时还会利用fdinfo目录下的文件句柄得到打开文件时的状态.
例如:
1.1)创建程序test.c,本程序在/tmp/目录下以O_WRONLY(只写)和O_SYNC(同步)方式打开temp文件.
-------------------------------------------------------
root@troy:/tmp# more test.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main ()
{
int fd;
fd = open("/tmp/temp", O_WRONLY|O_SYNC);
lseek(fd, 80L, SEEK_SET);
sleep(100);
close(fd);
return 0;
}
root@troy:/tmp# gcc test.c -o testfd
root@troy:/tmp# ./testfd &
-------------------------------------------------------
1.2)观察testfd程序打开的文件/tmp/temp
-------------------------------------------------------
cat /proc/$(lsof -w /tmp/temp|awk '/testfd/{print $2}')/fdinfo/3
pos: 80
flags: 0110001
-------------------------------------------------------
我们看到程序输出pos和flags两组数据,pos字段表示被打开文件的当前读写位置,flags表示以文件方式打开该文件.
pos为80表示从文件起始位置移动80个字节的位置.
flags为0110001中的xxxxxx1表示以只写方式打开文件,如果是只读则为xxxxxx0,如果可读可写则为xxxxxx2,
其中的xx1xxxx表示以同步方式(O_SYNC)打开文件,如果改用以O_ASYNC方式打开文件,则为xx2xxxx,
如果同时指定了O_SYNC和O_ASYNC两种方式打开文件,结果则为xx3xxxx.
如果我们增加了O_APPEND方式打开文件,结果则为xxx2xxx.
如果我们增加了O_NONBLOCK方式打开文件,结果则为xxx4xxx.
如果同时指定了O_APPEND和NONBLOCK两种方式,结果则为xxx6xxx.
最后指明一下O_ASYNC用于打开终端和socket文件,默认产生SIGIO信号.
而O_NONBLOCK表示不阻塞打开的文件,只用于FIFO的管道文件中.
2)查看对某个目录的使用情况
我们先执行上个试验的程序.
-------------------------------------------------------
root@troy:~# /tmp/testfd &
[1] 17021
root@troy:~# lsof +d /tmp/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
gedit 2531 troy 7u unix 0xffff880029a49b00 0t0 17106 /tmp/gedit.troy.917415843
testfd 17021 root txt REG 8,1 8617 262475 /tmp/testfd
testfd 17021 root 3w REG 8,1 0 262412 /tmp/temp
bash 3926 troy cwd DIR 8,1 4096 262149 /tmp
bash 4001 troy cwd DIR 8,1 4096 262149 /tmp
-------------------------------------------------------
如果不加参数+d呢?这里我们只看到了用户的当前使用目录,如下:
-------------------------------------------------------
root@troy:~# lsof -w /tmp
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 3926 troy cwd DIR 8,1 4096 262149 /tmp
bash 4001 troy cwd DIR 8,1 4096 262149 /tmp
-------------------------------------------------------
有什么区别吗?
加+d参数的情况下,lsof会遍列所有的进程,以及进程下所有的fd,fdinfo,cwd,root,exec,maps,以查找被程序占用中的目录.
而不加参数+d的情况下,lsof只会遍列所有进程的cwd,cwd是用户当前目录的软链接.如下:
-------------------------------------------------------
root@troy:~# ls -l /proc/3926/cwd
lrwxrwxrwx 1 troy troy 0 2011-02-09 19:23 /proc/3926/cwd -> /tmp
-------------------------------------------------------
3)查看某个进程的使用情况
-------------------------------------------------------
troy@troy:/proc/23294$ lsof -p 23294
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ssh 23294 troy cwd DIR 8,1 4096 262149 /tmp
ssh 23294 troy rtd DIR 8,1 4096 2 /
ssh 23294 troy txt REG 8,1 339712 1058082 /usr/bin/ssh
ssh 23294 troy mem REG 8,1 51712 787472 /lib/libnss_files-2.11.1.so
ssh 23294 troy mem REG 8,1 43552 787456 /lib/libnss_nis-2.11.1.so
ssh 23294 troy mem REG 8,1 97256 787430 /lib/libnsl-2.11.1.so
ssh 23294 troy mem REG 8,1 35712 787454 /lib/libnss_compat-2.11.1.so
ssh 23294 troy mem REG 8,1 135745 787466 /lib/libpthread-2.11.1.so
ssh 23294 troy mem REG 8,1 10224 787804 /lib/libkeyutils-1.2.so
ssh 23294 troy mem REG 8,1 31168 1050775 /usr/lib/libkrb5support.so.0.1
ssh 23294 troy mem REG 8,1 14584 798518 /lib/libcom_err.so.2.1
ssh 23294 troy mem REG 8,1 154048 1050756 /usr/lib/libk5crypto.so.3.1
ssh 23294 troy mem REG 8,1 803192 1050769 /usr/lib/libkrb5.so.3.3
ssh 23294 troy mem REG 8,1 14696 795838 /lib/libdl-2.11.1.so
ssh 23294 troy mem REG 8,1 1572232 787469 /lib/libc-2.11.1.so
ssh 23294 troy mem REG 8,1 213784 1050761 /usr/lib/libgssapi_krb5.so.2.2
ssh 23294 troy mem REG 8,1 93000 787444 /lib/libresolv-2.11.1.so
ssh 23294 troy mem REG 8,1 92752 786985 /lib/libz.so.1.2.3.3
ssh 23294 troy mem REG 8,1 1622304 796093 /lib/libcrypto.so.0.9.8
ssh 23294 troy mem REG 8,1 136936 787431 /lib/ld-2.11.1.so
ssh 23294 troy 0u CHR 136,20 0t0 23 /dev/pts/20
ssh 23294 troy 1u CHR 136,20 0t0 23 /dev/pts/20
ssh 23294 troy 2u CHR 136,20 0t0 23 /dev/pts/20
ssh 23294 troy 3u IPv4 1603924 0t0 TCP troy.local:41879->10.1.1.7:ssh (ESTABLISHED)
ssh 23294 troy 4w FIFO 0,8 0t0 1603904 pipe
ssh 23294 troy 5u CHR 136,19 0t0 22 /dev/pts/19
ssh 23294 troy 6r CHR 5,0 0t0 1129 /dev/tty
ssh 23294 troy 7u CHR 136,21 0t0 24 /dev/pts/21
ssh 23294 troy 8u CHR 136,20 0t0 23 /dev/pts/20
ssh 23294 troy 9u CHR 136,20 0t0 23 /dev/pts/20
ssh 23294 troy 10u CHR 136,20 0t0 23 /dev/pts/20
-------------------------------------------------------
lsof程序会跟据用户指定的PID,遍列/proc/目录找到该PID,在/proc/PID目录下依次打开stat,maps,fd,fdinfo.
stat文件包含了当前进程的信息.
当前进程的stat如下:
23294 (ssh) S 23291 23294 23294 34837 23294 4202496 836 0 0 0 8 10 0 0 20 0 1 0 29282141 39632896 658 18446744073709551615 140114439372800 140114439700540 140733214155456 140733214149016 140114423930835 0 0 4096 136331271 18446744071580239593 0 0 17 1 0 0 0 0 0
maps文件包含映像的文件:
当前进程的maps如下:
7f6eecf42000-7f6eecf4e000 r-xp 00000000 08:01 787472 /lib/libnss_files-2.11.1.so
7f6eecf4e000-7f6eed14d000 ---p 0000c000 08:01 787472 /lib/libnss_files-2.11.1.so
7f6eed14d000-7f6eed14e000 r--p 0000b000 08:01 787472 /lib/libnss_files-2.11.1.so
7f6eed14e000-7f6eed14f000 rw-p 0000c000 08:01 787472 /lib/libnss_files-2.11.1.so
7f6eed14f000-7f6eed159000 r-xp 00000000 08:01 787456 /lib/libnss_nis-2.11.1.so
7f6eed159000-7f6eed358000 ---p 0000a000 08:01 787456 /lib/libnss_nis-2.11.1.so
7f6eed358000-7f6eed359000 r--p 00009000 08:01 787456 /lib/libnss_nis-2.11.1.so
7f6eed359000-7f6eed35a000 rw-p 0000a000 08:01 787456 /lib/libnss_nis-2.11.1.so
7f6eed35a000-7f6eed371000 r-xp 00000000 08:01 787430 /lib/libnsl-2.11.1.so
7f6eed371000-7f6eed570000 ---p 00017000 08:01 787430 /lib/libnsl-2.11.1.so
7f6eed570000-7f6eed571000 r--p 00016000 08:01 787430 /lib/libnsl-2.11.1.so
7f6eed571000-7f6eed572000 rw-p 00017000 08:01 787430 /lib/libnsl-2.11.1.so
后省略.
这里用pmap 23294也可以找到加载的文件与虚拟地址的对映.
fd,fdinfo我们已经分析过了,当lsof找到/proc/23294/3时,发现是个socket文件,如下:
----------------------------------------------------
troy@troy:/proc/23294/fd$ ls -l
total 0
lrwx------ 1 troy troy 64 2011-02-11 02:47 0 -> /dev/pts/20
lrwx------ 1 troy troy 64 2011-02-11 02:47 1 -> /dev/pts/20
lrwx------ 1 troy troy 64 2011-02-11 02:47 10 -> /dev/pts/20
lrwx------ 1 troy troy 64 2011-02-11 01:07 2 -> /dev/pts/20
lrwx------ 1 troy troy 64 2011-02-11 02:47 3 -> socket:[1603924]
l-wx------ 1 troy troy 64 2011-02-11 02:47 4 -> pipe:[1603904]
lrwx------ 1 troy troy 64 2011-02-11 02:47 5 -> /dev/pts/19
lr-x------ 1 troy troy 64 2011-02-11 02:47 6 -> /dev/tty
lrwx------ 1 troy troy 64 2011-02-11 02:47 7 -> /dev/pts/21
lrwx------ 1 troy troy 64 2011-02-11 02:47 8 -> /dev/pts/20
lrwx------ 1 troy troy 64 2011-02-11 02:47 9 -> /dev/pts/20
----------------------------------------------------
此时会依次打开以下的文件,对网络套字接进行分析,各文件作用如下:
/proc/net/raw ---->原始套接字
/proc/net/unix ---->UNIX套接字
/proc/net/sockstat ---->当前套接字的使用情况
/proc/net/tcp ---->TCP套接字
/proc/net/udp ---->UDP套接字
/proc/net/udplite --->UDP无线通讯套接字
在/proc/net/tcp会找到对映的inode,socket:[1603924]的inode为1603924,而tcp中sl为12的一行正是这个socket服务.如下:
----------------------------------------------------
more /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:0087 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8984 1 ffff8800677d1380 300 0 0 2 -1
1: 00000000:0369 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8575 1 ffff8800677d0d00 300 0 0 2 -1
2: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8673 1 ffff880068c51a00 300 0 0 2 -1
3: 00000000:1770 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 5350 1 ffff880068c50680 300 0 0 2 -1
4: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 4315 1 ffff880068c50000 300 0 0 2 -1
5: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 25571 1 ffff88001a06c780 300 0 0 2 -1
6: 00000000:0BB8 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 7881 1 ffff8800677d0680 300 0 0 2 -1
7: 00000000:BD59 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8986 1 ffff880068c52080 300 0 0 2 -1
8: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 6304 1 ffff880068c50d00 300 0 0 2 -1
9: 4506010A:D6E9 0701010A:0016 01 00000000:00000000 02:00028405 00000000 1502 0 1603452 2 ffff880057896180 22 4 8 5 -1
10: 4506010A:89A5 0701010A:0016 01 00000000:00000000 02:00091EFF 00000000 1502 0 1672803 2 ffff88001a068680 25 4 18 4 -1
11: 4506010A:872E 0701010A:0016 01 00000000:00000000 02:0004B77C 00000000 1502 0 1177942 2 ffff880057893a80 125 4 0 3 2
12: 4506010A:A397 0701010A:0016 01 00000000:00000000 02:0004D6A6 00000000 1502 0 1603924 2 ffff880057894e00 23 4 0 5 -1
13: 4506010A:BD31 0701010A:0016 01 00000000:00000000 02:000139A5 00000000 1502 0 1345002 2 ffff880057897500 22 4 0 5 -1
14: 4506010A:8F21 0701010A:0016 01 00000000:00000000 02:000192BE 00000000 1502 0 1351794 2 ffff880057896800 25 4 12 4 -1
15: 4506010A:8AD1 0701010A:0016 01 00000000:00000000 02:00094915 00000000 1502 0 1447912 2 ffff880068c55b00 21 4 14 4 -1
----------------------------------------------------
其中local_address代表本地的IP和端口
4506010A(本地地址)的45转化为十进制是69,06转化为十制制是6,01转化为十进制是1,0A转化为十进制是10,倒过来也就是10.1.1.69,是本地地址.
A397(本地端口)转化为十进制是41879,也就是本地端口
rem_address代表远程IP和端口
0701010A(远程地址):10.1.1.7
0016(远程端口)22
其它参数都是内核调试时使用
uid就是用户的UID
4)显示所属user进程打开的文件
----------------------------------------------------
root@troy:/proc/2554# lsof -u test -w
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
su 2554 test cwd DIR 8,1 4096 2 /
su 2554 test rtd DIR 8,1 4096 2 /
su 2554 test txt REG 8,1 36864 262185 /bin/su
su 2554 test mem REG 8,1 27024 797476 /lib/libnss_lsass.so.2.0.0
su 2554 test mem REG 8,1 10272 1102794 /usr/lib/gconv/IBM850.so
su 2554 test mem REG 8,1 14392 1102782 /usr/lib/gconv/UTF-16.so
su 2554 test mem REG 8,1 43528 795516 /lib/security/pam_gnome_keyring.so
su 2554 test mem REG 8,1 256768 787477 /lib/libdbus-1.so.3.4.0
su 2554 test mem REG 8,1 14536 1052877 /usr/lib/libck-connector.so.0.0.0
su 2554 test mem REG 8,1 10360 795488 /lib/security/pam_ck_connector.so
su 2554 test mem REG 8,1 14344 787928 /lib/libgpg-error.so.0.4.0
su 2554 test mem REG 8,1 491000 787918 /lib/libgcrypt.so.11.5.2
su 2554 test mem REG 8,1 92752 786985 /lib/libz.so.1.2.3.3
su 2554 test mem REG 8,1 67896 1055840 /usr/lib/libtasn1.so.3.1.7
su 2554 test mem REG 8,1 10224 787804 /lib/libkeyutils-1.2.so
su 2554 test mem REG 8,1 31168 1050775 /usr/lib/libkrb5support.so.0.1
su 2554 test mem REG 8,1 14584 798518 /lib/libcom_err.so.2.1
以下略
----------------------------------------------------
通过strace,我们知道lsof通过stat系统调用得到这个进程的目录owner,正是我们要找的用户进程.
如下:
stat("/proc/2554/", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/2554/stat", O_RDONLY) = 4
read(4, "2554 (su) S 2533 2554 2533 34817"..., 4096) = 241
最后lsof通过调用cwd,root,fd,fdinfo,maps以及网络套接字显示输出用户进程所使用的文件.
5)显示网络服务
----------------------------------------------------
root@troy:~# lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
smbd 767 root 22u IPv6 4410 0t0 TCP *:microsoft-ds (LISTEN)
smbd 767 root 23u IPv6 4412 0t0 TCP *:netbios-ssn (LISTEN)
sshd 787 root 3u IPv4 4227 0t0 TCP *:ssh (LISTEN)
sshd 787 root 4u IPv6 4229 0t0 TCP *:ssh (LISTEN)
avahi-dae 809 avahi 13u IPv4 4568 0t0 UDP *:mdns
avahi-dae 809 avahi 14u IPv4 4569 0t0 UDP *:50511
dhclient 883 root 5u IPv4 4530 0t0 UDP *:bootpc
Xorg 912 root 1u IPv6 4705 0t0 TCP *:x11 (LISTEN)
Xorg 912 root 3u IPv4 4706 0t0 TCP *:x11 (LISTEN)
dcerpcd 1132 root 15u IPv4 8845 0t0 TCP *:loc-srv (LISTEN)
dcerpcd 1132 root 16u IPv4 8846 0t0 UDP *:loc-srv
eventlogd 1261 root 14u IPv4 8850 0t0 TCP *:55846 (LISTEN)
exim4 1563 Debian-exim 3u IPv4 6359 0t0 TCP localhost:smtp (LISTEN)
以下略
----------------------------------------------------
lsof通过遍列所有进程的所有文件句柄,找到网络套接字,再通过/proc/net/下面的网络信息得到具体的套接字信息.