一、概述
在linux中,所有東西都是以文件的形式存在的,所以我們在linux上的操作都是通過對文件的操作來執行我們所需要的邏輯,比如我們對文件數據的訪問,修改,訪問網絡的連接等,剛好lsof(list open file)命令用於查看進程打開的文件,打開文件的進程,進程打開的端口(TCP、UDP)。找回/恢復刪除的文件。是十分方便的系統監視工具,因為lsof命令需要訪問核心內存和各種文件,所以需要root用戶執行。
安裝命令:yum install lsof #centos系統
二、語法和內容含義
2.1、使用語法
語法:lsof [options] filename
常用選項:
無選項 #默認列出所有打開的文件相關信息
file #列出打開文件存在的進程
-a #使用AND邏輯,合並選項輸出內容
-c<進程名> #列出指定進程所打開的文件
-g #列出GID號進程詳情
-d<文件號> #列出占用該文件描述符的進程
+d<目錄> #列出目錄下被打開的文件
+D<目錄> #遞歸列出目錄下被打開的文件
-n<目錄> #列出使用NFS的文件
-i<條件> #列出符合條件的進程。(4、6、協議、:端口、 @ip )
-p<進程號> #列出指定進程號所打開的文件
-u #列出UID號進程詳情
-U #獲取 UNIX 套接口地址
-t #列出進程
-h #顯示幫助信息
-v #顯示版本信息
2.2、內容含義
首先我們使用lsof | head 命令查看一下
[root@lgh ~]# lsof | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 253,0 4096 2 /
init 1 root rtd DIR 253,0 4096 2 /
init 1 root txt REG 253,0 150352 8519721 /sbin/init
init 1 root mem REG 253,0 66432 1310749 /lib64/libnss_files-2.12.so
init 1 root DEL REG 253,0 1310733 /lib64/libc-2.12.so
init 1 root DEL REG 253,0 1310744 /lib64/libgcc_s-4.4.7-20120601.so.1.#prelink#.AXbpAw
init 1 root DEL REG 253,0 1310761 /lib64/librt-2.12.so
init 1 root DEL REG 253,0 1310757 /lib64/libpthread-2.12.so.#prelink#.6p24pv
init 1 root DEL REG 253,0 1310783 /lib64/libdbus-1.so.3.4.0.#prelink#.M6wKKU
lsof -R +d /dev | head 命令查看一波(主要看FD這列),並且相比上面增加了PPID列
[root@mwpl003 ~]# lsof -R +d /dev | head
COMMAND PID PPID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 0 root 0u CHR 1,3 0t0 4025 /dev/null
init 1 0 root 1u CHR 1,3 0t0 4025 /dev/null
init 1 0 root 2u CHR 1,3 0t0 4025 /dev/null
udevd 1872 1 root 0u CHR 1,3 0t0 4025 /dev/null
udevd 1872 1 root 1u CHR 1,3 0t0 4025 /dev/null
udevd 1872 1 root 2u CHR 1,3 0t0 4025 /dev/null
rserver 3375 1 rstudio-server 0u CHR 1,3 0t0 4025 /dev/null
rserver 3375 1 rstudio-server 1u CHR 1,3 0t0 4025 /dev/null
rserver 3375 1 rstudio-server 2u CHR 1,3 0t0 4025 /dev/null
每列的基本含義如下:
COMMAND:進程的名稱
PID:進程標識符
PPID:父進程標識符(需要指定-R參數)
USER:進程所有者
FD:文件描述符,應用程序通過文件描述符識別該文件。
TYPE:文件類型
DEVICE:指定磁盤的名稱
SIZE/OFF:文件的大小
NODE:索引節點(文件在磁盤上的標識)
NAME:打開文件的確切名稱
其中FD文件描述符列表如下:
cwd:表示current work dirctory,即:應用程序的當前工作目錄,這是該應用程序啟動的目錄,除非它本身對這個目錄進行更改
txt:該類型的文件是程序代碼,如應用程序二進制文件本身或共享庫,如上列表中顯示的 /sbin/init 程序
lnn:library references (AIX);
er:FD information error (see NAME column);
jld:jail directory (FreeBSD);
ltx:shared library text (code and data);
mxx :hex memory-mapped type number xx.
m86:DOS Merge mapped file;
mem:memory-mapped file;
mmap:memory-mapped device;
pd:parent directory;
rtd:root directory;
tr:kernel trace file (OpenBSD);
v86 VP/ix mapped file;
0:表示標准輸出
1:表示標准輸入
2:表示標准錯誤
一般在標准輸出、標准錯誤、標准輸入后還跟着文件狀態模式:
u:表示該文件被打開並處於讀取/寫入模式。
r:表示該文件被打開並處於只讀模式。
w:表示該文件被打開並處於。
空格:表示該文件的狀態模式為unknow,且沒有鎖定。
-:表示該文件的狀態模式為unknow,且被鎖定。
其中TYPE文件類型列表如下:
DIR:表示目錄
CHR:表示字符類型
BLK:塊設備類型
UNIX:UNIX域套接字
FIFO:先進先出(FIFO)隊列
IPv4:網際協議(IP)套接字
三、實踐
查看誰正在使用某個文件,也就是說查找某個文件相關的進程
[root@localhost omc]# lsof /var/log/messages
遞歸查看某個目錄的文件信息
[root@localhost omc]# lsof /home/omc/
==> [root@localhost omc]# lsof +D /home/omc/ 【使用了+D,對應目錄下的所有子目錄和文件都會被列出】
列出某個用戶打開的文件信息
[root@localhost omc]# lsof -u root
列出某個程序進程所打開的文件信息
[root@localhost omc]#lsof –c sshd
-c【command】 選項將會列出所有以mysql這個進程開頭的程序的文件,其實你也可以寫成 lsof | grep sshd, 但是第一種方法明顯比第二種方法要少打幾個字符了
列出某個IP的連接信息
[root@localhost omc]# lsof -i @192.168.25.133
根據IP分類顯示當前環境的連接信息
[root@localhost omc]# lsof -i 4 #列舉IPV4
[root@localhost omc]# lsof -i 6 #列舉IPV6
列出TCP/UDP的連接信息
[root@localhost omc]# lsof -i tcp
[root@localhost omc]# lsof -i udp
[root@localhost omc]# lsof -i tcp:22
列出除了某個用戶外的被打開的文件信息
[root@localhost omc]#lsof -u ^root
列出某個用戶的所有活躍的網絡端口
[root@localhost omc]#lsof -a -u root -i
通過某個進程號顯示該進行打開的文件
[root@localhost omc]# lsof -p 2601
[root@localhost omc]# lsof -p 2601,2602,2603
列出所有網絡文件系統
[root@localhost omc]# lsof –N
根據文件描述列出對應的文件信息
lsof -d description(like 2)
例如:lsof -d txt
例如:lsof -d 1
例如:lsof -d 2
說明:0表示標准輸入,1表示標准輸出,2表示標准錯誤,從而可知:所以大多數應用程序所打開的文件的 FD 都是從 3 開始
據文件描述范圍列出文件信息
[root@localhost omc]# lsof -d 2-3
列出COMMAND列中包含字符串" sshd",且文件描符的類型為txt的文件信息
[root@localhost omc]# lsof -c sshd -a -d txt
列出被進程號為1234的進程所打開的所有IPV4 network files
[root@localhost omc]# lsof -i 4 -a -p 1234
列出目前連接主機hadoop且端口為:20,21,22,25,53,80相關的所有文件信息,且每隔3秒不斷的執行lsof指令
[root@localhost omc]# lsof -i @hadoop:20,21,22,25,53,80 -r 3
四、實踐2
1、lsof -a -u root -d 2 | head #列出是root用戶,並且DF為2的文件,-a只有兩者滿足都滿足要求才列出
[root@lgh ~]# lsof -a -u root -d 2 | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root 2u CHR 1,3 0t0 4025 /dev/null
udevd 1872 root 2u CHR 1,3 0t0 4025 /dev/null
auditd 3525 root 2u CHR 1,3 0t0 4025 /dev/null
rsyslogd 3559 root 2w REG 253,0 2092 4457009 /var/log/messages
irqbalanc 3594 root 2u CHR 1,3 0t0 4025 /dev/null
cupsd 3689 root 2w CHR 1,3 0t0 4025 /dev/null
acpid 3721 root 2u CHR 1,3 0t0 4025 /dev/null
hald-runn 3734 root 2u CHR 1,3 0t0 4025 /dev/null
hald-addo 3774 root 2u CHR 1,3 0t0 4025 /dev/null
2、lsof +d /bin/ #顯示/bin當前目錄下所有打開的文件,如果是想遞歸的打開則使用選項 +D即可
[root@lgh ~]# lsof +d /bin/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dbus-daem 3668 dbus txt REG 253,0 339080 12582956 /bin/dbus-daemon
bash 6012 root txt REG 253,0 942200 12582957 /bin/bash
dbus-daem 9311 gdm txt REG 253,0 339080 12582956 /bin/dbus-daemon
bash 11017 root txt REG 253,0 942200 12582957 /bin/bash
3、lsof -i | head -20 | tail #使用 -i 選項顯示網絡連接
[root@lgh ~]# lsof -i | head -20 | tail
rpcbind 3612 rpc 8u IPv4 16143 0t0 TCP *:sunrpc (LISTEN)
rpcbind 3612 rpc 9u IPv6 16144 0t0 UDP *:sunrpc
rpcbind 3612 rpc 10u IPv6 16145 0t0 UDP *:819
rpcbind 3612 rpc 11u IPv6 16146 0t0 TCP *:sunrpc (LISTEN)
rpc.statd 3634 rpcuser 5r IPv4 16223 0t0 UDP localhost.localdomain:842
rpc.statd 3634 rpcuser 8u IPv4 16228 0t0 UDP *:53636
rpc.statd 3634 rpcuser 9u IPv4 16231 0t0 TCP *:36415 (LISTEN)
rpc.statd 3634 rpcuser 10u IPv6 16234 0t0 UDP *:52108
rpc.statd 3634 rpcuser 11u IPv6 16237 0t0 TCP *:38611 (LISTEN)
cupsd 3689 root 6u IPv6 16394 0t0 TCP localhost.localdomain:ipp (LISTEN)
4、lsof -i 4 | head #僅獲取IPV4的流量 ,如果想獲取IPV6的流量的話,把4改成6即可
[root@lgh ~]# lsof -i 4 | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
haproxy 1523 root 0u IPv4 871803 0t0 UDP *:50203
haproxy 1523 root 4u IPv4 871797 0t0 TCP *:ff-fms (LISTEN)
haproxy 1523 root 5u IPv4 871798 0t0 TCP *:panagolin-ident (LISTEN)
haproxy 1523 root 6u IPv4 871799 0t0 TCP *:scp-config (LISTEN)
rserver 3375 rstudio-server 6u IPv4 15668 0t0 TCP *:msgsrvr (LISTEN)
rsyslogd 3559 root 4u IPv4 15950 0t0 UDP *:syslog
rpcbind 3612 rpc 6u IPv4 16141 0t0 UDP *:sunrpc
rpcbind 3612 rpc 7u IPv4 16142 0t0 UDP *:819
rpcbind 3612 rpc 8u IPv4 16143 0t0 TCP *:sunrpc (LISTEN)
5、lsof -itcp |head #顯示所有tcp連接,如果想顯示udp連接就把tcp改成udp即可
[root@lgh~]# lsof -itcp |head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
haproxy 1523 root 4u IPv4 871797 0t0 TCP *:ff-fms (LISTEN)
haproxy 1523 root 5u IPv4 871798 0t0 TCP *:panagolin-ident (LISTEN)
haproxy 1523 root 6u IPv4 871799 0t0 TCP *:scp-config (LISTEN)
rserver 3375 rstudio-server 6u IPv4 15668 0t0 TCP *:msgsrvr (LISTEN)
rpcbind 3612 rpc 8u IPv4 16143 0t0 TCP *:sunrpc (LISTEN)
rpcbind 3612 rpc 11u IPv6 16146 0t0 TCP *:sunrpc (LISTEN)
rpc.statd 3634 rpcuser 9u IPv4 16231 0t0 TCP *:36415 (LISTEN)
rpc.statd 3634 rpcuser 11u IPv6 16237 0t0 TCP *:38611 (LISTEN)
cupsd 3689 root 6u IPv6 16394 0t0 TCP localhost.localdomain:ipp (LISTEN)
6、lsof -i@192.168.88.133 #使用-i@host顯示該主機是否連接了指定主機,使用-i@host:port顯示該主機是否通過某個指定端口連接指定主機
[root@lgh ~]# lsof -i@192.168.88.133
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 20380 zookeeper 31u IPv4 207875803 0t0 TCP lgh:macbak->lgh1:60670 (ESTABLISHED)
java 20380 zookeeper 33u IPv4 207875808 0t0 TCP lgh:40232->lgh1:bmcpatrolagent (ESTABLISHED)
java 20380 zookeeper 46u IPv4 207879310 0t0 TCP lgh:eforward->lgh1:40134 (ESTABLISHED)
catalogd 21822 impala 277u IPv4 207882990 0t0 TCP lgh:40964->lgh1:med-ltp (ESTABLISHED)
catalogd 21822 impala 278u IPv6 207882991 0t0 TCP lgh:23020->lgh1:40058 (ESTABLISHED)
catalogd 21822 impala 279u IPv6 207882992 0t0 TCP lgh:23020->lgh1:40060 (ESTABLISHED)
You have mail in /var/spool/mail/root
[root@lgh ~]# lsof -i@192.168.88.133:60670
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 20380 zookeeper 31u IPv4 207875803 0t0 TCP lgh:macbak->lgh1:60670 (ESTABLISHED)
7、lsof -i -stcp:LISTEN |head #找出所有監聽的文件,把LISTEN換成ESTABLISHED表示顯示所有建立連接的文件
[root@lgh ~]# lsof -i -stcp:LISTEN |head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
haproxy 1523 root 4u IPv4 871797 0t0 TCP *:ff-fms (LISTEN)
haproxy 1523 root 5u IPv4 871798 0t0 TCP *:panagolin-ident (LISTEN)
haproxy 1523 root 6u IPv4 871799 0t0 TCP *:scp-config (LISTEN)
rserver 3375 rstudio-server 6u IPv4 15668 0t0 TCP *:msgsrvr (LISTEN)
rpcbind 3612 rpc 8u IPv4 16143 0t0 TCP *:sunrpc (LISTEN)
rpcbind 3612 rpc 11u IPv6 16146 0t0 TCP *:sunrpc (LISTEN)
rpc.statd 3634 rpcuser 9u IPv4 16231 0t0 TCP *:36415 (LISTEN)
rpc.statd 3634 rpcuser 11u IPv6 16237 0t0 TCP *:38611 (LISTEN)
cupsd 3689 root 6u IPv6 16394 0t0 TCP localhost.localdomain:ipp (LISTEN)
8、lsof -u root | head #指定root用戶打開的所有文件,可以通過 -u ^root取反,表示非root用戶打開的文件,kill -9 lsof -u hive -t 表示殺掉hive所有的進程
[root@lgh ~]# lsof -u root | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 253,0 4096 2 /
init 1 root rtd DIR 253,0 4096 2 /
init 1 root txt REG 253,0 150352 8519721 /sbin/init
init 1 root mem REG 253,0 66432 1310749 /lib64/libnss_files-2.12.so
init 1 root DEL REG 253,0 1310733 /lib64/libc-2.12.so
init 1 root DEL REG 253,0 1310744 /lib64/libgcc_s-4.4.7-20120601.so.1.#prelink#.AXbpAw
9、 lsof -c haproxy #顯示指定haproxy命令的連接文件,使用-p參數則是指定端口
[root@lgh ~]# lsof -c haproxy
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
haproxy 1523 root cwd DIR 253,1 4096 57939112 /data/hive/transfer_baseinfo
haproxy 1523 root rtd DIR 253,0 4096 2 /
haproxy 1523 root txt REG 253,0 3769897 2376812 /usr/local/sbin/haproxy
haproxy 1523 root DEL REG 253,0 1310733 /lib64/libc-2.12.so
haproxy 1523 root DEL REG 253,0 1310836 /lib64/ld-2.12.so
haproxy 1523 root 0u IPv4 871803 0t0 UDP *:50203
haproxy 1523 root 3u unix 0xffff88204e2343c0 0t0 871795 /var/run/haproxy/info.sock.1522.tmp
haproxy 1523 root 4u IPv4 871797 0t0 TCP *:ff-fms (LISTEN)
五、數據恢復
當進程打開了某個文件時,只要該進程保持打開該文件,即使將其刪除,它依然存在於磁盤中。這意味着,進程並不知道文件已經被刪除,它仍然可以向打開該文件時提供給它的文件描述符進行讀取和寫入。除了該進程之外,這個文件是不可見的,因為已經刪除了其相應的目錄索引節點。
在/proc 目錄下,其中包含了反映內核和進程樹的各種文件。/proc目錄掛載的是在內存中所映射的一塊區域,所以這些文件和目錄並不存在於磁盤中,因此當我們對這些文件進行讀取和寫入時,實際上是在從內存中獲取相關信息。大多數與 lsof 相關的信息都存儲於以進程的 PID 命名的目錄中,即 /proc/1234 中包含的是 PID 為 1234 的進程的信息。每個進程目錄中存在着各種文件,它們可以使得應用程序簡單地了解進程的內存空間、文件描述符列表、指向磁盤上的文件的符號鏈接和其他系統信息。
lsof 程序使用該信息和其他關於內核內部狀態的信息來產生其輸出。所以lsof 可以顯示進程的文件描述符和相關的文件名等信息。也就是我們通過訪問進程的文件描述符可以找到該文件的相關信息。當系統中的某個文件被意外地刪除了,只要這個時候系統中還有進程正在訪問該文件,那么我們就可以通過lsof從/proc目錄下恢復該文件的內容
我們使用 /var/log/messages做測試:
首先我們用lsof查看下/var/log/messages這個文件的連接
[root@lgh2 fd]# lsof | grep messages
rsyslogd 6511 root 6w REG 253,0 647273 34816846 /var/log/messages
in:imjour 6511 6543 root 6w REG 253,0 647273 34816846 /var/log/messages
rs:main 6511 6553 root 6w REG 253,0 647273 34816846 /var/log/messages
然后我們使用命令rm -f /var/log/messages刪除文件,繼續使用lsof命令查看,已經顯示刪除
[root@lgh2 fd]# lsof | grep messages
rsyslogd 6511 root 6w REG 253,0 647273 34816846 /var/log/messages (deleted)
in:imjour 6511 6543 root 6w REG 253,0 647273 34816846 /var/log/messages (deleted)
rs:main 6511 6553 root 6w REG 253,0 647273 34816846 /var/log/messages (deleted)
然后我們cd /proc/6511/fd #6511表示進程號,然后我們ll查看一下目錄
[root@lgh2 fd]# ll
total 0
lr-x------ 1 root root 64 Oct 12 04:22 0 -> /dev/null
l-wx------ 1 root root 64 Oct 12 04:22 1 -> /dev/null
l-wx------ 1 root root 64 Oct 12 04:22 2 -> /dev/null
lr-x------ 1 root root 64 Oct 12 04:22 3 -> anon_inode:inotify
lrwx------ 1 root root 64 Oct 12 04:22 4 -> socket:[36279]
lr-x------ 1 root root 64 Oct 12 04:22 5 -> /run/log/journal/0b933fe64005419d8f16599287df47be/system.journal
l-wx------ 1 root root 64 Oct 12 04:22 6 -> /var/log/messages (deleted) #這里發現6這個文件描述符指向這個文件/var/log/messages
我們cat查看一下6這個文件
[root@lgh2 fd]# cat 6 | head -20 #這個文件就是我們對應的/var/log/messages文件
Sep 22 03:12:45 lgh2 chronyd[6237]: Selected source 120.25.115.20
Sep 22 03:12:45 lgh2 chronyd[6237]: System clock wrong by -43210.956291 seconds, adjustment started
Sep 22 03:15:01 lgh2 systemd: Started Session 881 of user root.
Sep 22 03:15:21 lgh2 systemd: Time has been changed
Sep 22 03:15:27 lgh2 chronyd[6237]: Forward time jump detected!
Sep 22 03:15:27 lgh2 chronyd[6237]: Can't synchronise: no selectable sources
Sep 22 03:17:36 lgh2 chronyd[6237]: Selected source 119.28.183.184
Sep 22 03:17:36 lgh2 chronyd[6237]: System clock wrong by -43211.807006 seconds, adjustment started
Sep 22 03:18:23 lgh2 chronyd[6237]: Selected source 120.25.115.20
Sep 22 03:18:41 lgh2 chronyd[6237]: Selected source 119.28.183.184
Sep 22 03:20:01 lgh2 systemd: Started Session 882 of user root.
Sep 22 03:20:01 lgh2 systemd: Started Session 883 of user root.
Sep 22 03:20:21 lgh2 systemd: Time has been changed
Sep 22 03:20:26 lgh2 chronyd[6237]: Forward time jump detected!
Sep 22 03:20:26 lgh2 chronyd[6237]: Can't synchronise: no selectable sources
Sep 22 03:22:36 lgh2 chronyd[6237]: Selected source 5.79.108.34
Sep 22 03:22:36 lgh2 chronyd[6237]: System clock wrong by -43211.562700 seconds, adjustment started
Sep 22 03:22:55 lgh2 chronyd[6237]: Selected source 120.25.115.20
Sep 22 03:25:01 lgh2 systemd: Started Session 884 of user root.
Sep 22 03:25:22 lgh2 systemd: Time has been changed
然后我們使用命令 cat /proc/6511/fd/6 > /var/log/messages 還原數據,然后我們繼續使用lsof命令查看
[root@lgh2 fd]# lsof | grep messages
rsyslogd 6511 root 6w REG 253,0 213 34816872 /var/log/messages
in:imjour 6511 6543 root 6w REG 253,0 213 34816872 /var/log/messages
rs:main 6511 6553 root 6w REG 253,0 213 34816872 /var/log/messages
還原成功了
