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/下面的网络信息得到具体的套接字信息.

相关内容

    暂无相关文章