代码改变世界

Linux lsof工具介绍

2012-05-03 23:30  bangerlee  阅读(6867)  评论(0编辑  收藏  举报

引言

Linux fuser工具介绍》一文中,与大家一起学习了fuser工具的使用方法。"lsof"——list open fileslsof也是Linux下用于查看打开的文件以及相关联进程信息的工具,相比fuser提供更强大的功能,下面我们就来学习lsof的使用方法。

 

lsof输出说明

直接执行lsof,将输出系统中所有打开文件的信息,这里说的文件不单指一般的文件,还包括目录、socket套接字、设备文件和命名管道:

#lsof
COMMAND     PID       USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
init          1       root  cwd       DIR                8,2     4096          2 /
init          1       root  rtd       DIR                8,2     4096          2 /
init          1       root  txt       REG                8,2    40784    6488145 /sbin/init
init          1       root  mem       REG                8,2    19114    3874831 /lib64/libdl-2.11.1.so
init          1       root   10u     FIFO               0,15      0t0       2677 /dev/initctl
……

每行显示一个打开的文件,各列含义如下:

  • COMMAND:与文件关联进程的名称
  • PID:进程PID
  • USER:拉起进程的用户
  • FD:指示进程与文件的关联关系
  • TYPE:指示文件类型
  • DEVICE:指示文件所在设备的设备号(major,minor)
  • SIZE/OFF:指示文件的大小或进程对文件操作的偏移量
  • NODE:文件索引标识
  • NAME:文件名

FD列值的含义与fuser查询结果中PID后接字符的含义相同,指示了进程与文件的关联关系,有以下常见取值:

  • cwd:进程工作目录
  • txt:进程由该文件拉起(如二进制文件或脚本)
  • rtd:进程的根目录
  • mem:内存映射文件
  • N(u/w/r):指示该文件为进程打开的第N个文件描述符,u为可读可写模式,w为可写模式,r为可读模式

TYPE列有以下常见取值:

  • REG:一般文件
  • DIR:目录
  • CHR:字符设备
  • BLK:块设备
  • FIFO:命名管道
  • PIPE:管道
  • IPV4:ipv4套接字
  • unix:unix域套接字

根据以上字段,我们就可以了解到哪个文件以何种关联方式与哪个进程关联。但单执行lsof输出太多,为获取必要输出,我们就得加一些过滤选项。

 

查询某个进程打开的文件

lsof常见的用法是查找进程打开的文件名称和文件数目,以下我们使用lsof查看pid14586syslog-ng进程使用了哪些文件:

# lsof -p 14586
COMMAND     PID USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
syslog-ng 14586 root  cwd    DIR                8,2     4096       2 /
syslog-ng 14586 root  rtd    DIR                8,2     4096       2 /
syslog-ng 14586 root  txt    REG                8,2   386456 6488333 /sbin/syslog-ng
syslog-ng 14586 root  mem    REG                8,2    61467 3874842 /lib64/libnss_files-2.11.1.so
syslog-ng 14586 root    0r   CHR                1,3      0t0    2707 /dev/null
syslog-ng 14586 root    1w   CHR                1,3      0t0    2707 /dev/null
syslog-ng 14586 root    2w   CHR                1,3      0t0    2707 /dev/null
syslog-ng 14586 root    3u  unix 0xffff8804787d59c0      0t0   23639 /var/lib/dhcp/dev/log
syslog-ng 14586 root    4u  unix 0xffff880475db46c0      0t0   23641 /dev/log
syslog-ng 14586 root    5w   REG                8,2  2268859 5858016 /var/log/messages

从以上查询结果可知,syslog-ng进程由/sbin/syslog-ng拉起,进程根目录和当前工作目录均为系统根目录,进程的标准输出、标准输入和标准出错输出均被重定向至/dev/null/var/log/messagessyslog-ng以可写模式打开。

 

Linux限制了进程能够打开文件的数目,通过如下命令可以查看该限制:

# ulimit -n
1024

 

若进程打开文件句柄的数目超过系统限制,则相应进程不能正常服务,使用如下方式我们可以查看各个进程打开文件句柄的数目:

# lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr| more

 

查询某个文件被哪些进程打开

lsof命令后直接接文件名,可以查到该文件被哪些进程打开:

# lsof /var/log/messages
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
syslog-ng 14586 root    5w   REG    8,2  2326134 5858016 /var/log/messages

要删除文件时要先中止进程,而不是直接删除这个文件。

 

umount文件系统时,如果文件系统中有打开的文件,那么umount操作会失败,报“device is busy”。这时可使用”lsof /dev/sdaX”显示sdaX文件系统中被打开的所有文件,再关闭所列文件。

 

进程的当前工作目录影响文件系统的卸载,这也是为什么在编写后台进程时需要将其工作目录设置为根目录的原因,

 

恢复删除文件

最后,来介绍使用lsof命令恢复被删文件的用法:某文件被删除,但从lsof能查到该文件仍被某进程打开,这时我们可以恢复被删文件。以下通过一个小程序说明该用法:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char** argv)
{
        int fd;
        char buf[10];
        fd = open("test.txt", O_RDONLY);
        read(fd, buf, 10);
        while(1)
        {
                sleep(2);
                printf("%s", buf);
        }
        return 0;
}

 

以上程序打开test.txt文件并定时输出该文件内容,在编译、拉起该程序之后,我们将test.txt文件删除,之后使用lsof查到打开该文件的进程:

# lsof | grep test.txt
ttt       12347       root    3r      REG                8,2        6    2334724 /tmp/lx/test.txt (deleted)

 

接着,在/proc中可以看到该进程打开的文件描述符如下:

# ll /proc/12347/fd
total 0
lrwx------ 1 root root 64 May  2 11:43 0 -> /dev/pts/1
lrwx------ 1 root root 64 May  2 11:43 1 -> /dev/pts/1
lrwx------ 1 root root 64 May  2 11:43 2 -> /dev/pts/1
lr-x------ 1 root root 64 May  2 11:43 3 -> /tmp/lx/test.txt (deleted)

 

执行以下命令我们即可将/tmp/lx/test.txt文件的内容恢复至/tmp/test.txt

# cat /proc/12347/fd/3 > /tmp/test.txt

 

当进程打开了某个文件时,只要该进程保持打开该文件,即使将文件删除,文件依然存在于磁盘中。进程并不知道文件已经被删除,它依然可以使用打开该文件时获取到的文件描述符进行读取和写入。除了该进程外,这个文件是不可见的,因为已经删除了其相应的目录条目。

 

小结

本文介绍了lsof的使用方法,包括lsof命令的输出格式,如何根据某进程查询其打开的文件,又如何查询某文件被哪些进程打开,以及判断进程打开文件数是否达到上限的方法、删除文件/卸载文件系统时需注意的事项,最后介绍了使用lsof恢复被删除文件的方法。