您的位置:首页 > 运维架构 > Linux

Linux调试工具lsof的深入分析

2011-10-25 17:15 429 查看

《Linux调试工具lsof的深入分析》

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/下面的网络信息得到具体的套接字信息.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 职场 休闲