lsof簡介
lsof(list open files)是一個列出目前系統打開檔案的工具。在linux環境下,任何事物都以檔案的形式存在,通過檔案不僅僅可以通路正常資料,還可以通路網絡連接配接 和硬體。是以如傳輸控制協定 (tcp) 和使用者資料報協定 (udp) 套接字等,系統在背景都為該應用程式配置設定了一個檔案描述符,無論這個檔案的本質如何,該檔案描述符為應用程式與基礎作業系統之間的互動提供了通用接口。因 為應用程式打開檔案的描述符清單提供了大量關于這個應用程式本身的資訊,是以通過lsof工具能夠檢視這個清單對系統監測以及排錯将是很有幫助的。
lsof使用
lsof輸出資訊含義
在終端下輸入lsof即可顯示系統打開的檔案,因為 lsof 需要通路核心記憶體和各種檔案,是以必須以 root 使用者的身份運作它才能夠充分地發揮其功能。
#lsof
command pid user fd type device size node name
init 1 root cwd dir 3,3 1024 2 /
init 1 root rtd dir 3,3 1024 2 /
init 1 root txt reg 3,3 38432 1763452 /sbin/init
init 1 root mem reg 3,3 106114 1091620 /lib/libdl-2.6.so
init 1 root mem reg 3,3 7560696 1091614 /lib/libc-2.6.so
init 1 root mem reg 3,3 79460 1091669 /lib/libselinux.so.1
init 1 root mem reg 3,3 223280 1091668 /lib/libsepol.so.1
init 1 root mem reg 3,3 564136 1091607 /lib/ld-2.6.so
init 1 root 10u fifo 0,15 1309 /dev/initctl
每行顯示一個打開的檔案,若不指定條件預設将顯示所有程序打開的所有檔案。lsof輸出各列資訊的意義如下:
command:程序的名稱
pid:程序辨別符
user:程序所有者
fd:檔案描述符,應用程式通過檔案描述符識别該檔案。如cwd、txt等
type:檔案類型,如dir、reg等
device:指定磁盤的名稱
size:檔案的大小
node:索引節點(檔案在磁盤上的辨別)
name:打開檔案的确切名稱
其中fd 列中的檔案描述符cwd 值表示應用程式的目前工作目錄,這是該應用程式啟動的目錄,除非它本身對這個目錄進行更改。txt 類型的檔案是程式代碼,如應用程式二進制檔案本身或共享庫,如上清單中顯示的 /sbin/init 程式。其次數值表示應用程式的檔案描述符,這是打開該檔案時傳回的一個整數。如上的最後一行檔案/dev/initctl,其檔案描述符為 10。u 表示該檔案被打開并處于讀取/寫入模式,而不是隻讀(r) 或隻寫 (w) 模式。同時還有大寫 的w 表示該應用程式具有對整個檔案的寫鎖。該檔案描述符用于確定每次隻能打開一個應用程式執行個體。初始打開每個應用程式時,都具有三個檔案描述符,0、1、2, 分别表示标準輸入、輸出和錯誤流。是以大多數應用程式所打開的檔案的 fd 都是從 3 開始。
與 fd 列相比,type 列則比較直覺。檔案和目錄分别稱為 reg 和 dir(在 solaris 中,稱為 vreg 和 vdir)。而chr 和 blk,分别表示字元和塊裝置; 或者 unix、fifo 和 ipv4,分别表示 unix 域套接字、先進先出 (fifo) 隊列和網際協定 (ip) 套接字。
lsof常用參數
lsof 常見的用法是查找應用程式打開的檔案的名稱和數目。可用于查找出某個特定應用程式将日志資料記錄到何處,或者正在跟蹤某個問題。
例如,linux限制了程序能夠打開檔案的數目。通常這個數值很大,是以不會産生問題,并且在需要時,應用程式可以請求更大的值(直到某
個上限)。如果你懷疑應用程式耗盡了檔案描述符,那麼可以使用 lsof 統計打開的檔案數目,以進行驗證。lsof文法格式是:
lsof [options] filename
常用的參數清單:
lsof filename 顯示打開指定檔案的所有程序
lsof -a 表示兩個參數都必須滿足時才顯示結果
lsof -c string 顯示command列中包含指定字元的程序所有打開的檔案
lsof -u username 顯示所屬user程序打開的檔案
lsof -g gid 顯示歸屬gid的程序情況
lsof +d /dir/ 顯示目錄下被程序打開的檔案
lsof +d /dir/ 同上,但是會搜尋目錄下的所有目錄,時間相對較長
lsof -d fd 顯示指定檔案描述符的程序
lsof -n 不将ip轉換為hostname,預設是不加上-n參數
lsof -i 用以顯示符合條件的程序情況
lsof -i[46] [protocol][@hostname|hostaddr][:service|port]
46 --> ipv4 or ipv6
protocol --> tcp or udp
hostname --> internet host name
hostaddr --> ipv4位址
service --> /etc/service中的 service name (可以不隻一個)
port --> 端口号 (可以不隻一個)
lsof +l/-l 打開或關閉檔案的連結數計算,當+l沒有指定時,所有的連結數都會顯示(預設);若+l後指定數字,則隻要連結數小于該數字的資訊會顯示;連結數會顯示在nlink列。
例如:+l1将顯示沒有unlinked的檔案資訊;+al1,則顯示指定檔案系統所有unlinked的檔案資訊。-l 預設參數,其後不能跟數字,将不顯示連結數資訊lsof +l1
lsof使用執行個體
檢視22端口現在運作的情況
# lsof -i :22
command pid user fd type device size node name
sshd 1409 root 3u ipv6 5678 tcp *:ssh (listen)
檢視所屬root使用者程序所打開的檔案類型為txt的檔案
# lsof -a -u root -d txt
command pid user fd type device size node name
init 1 root txt reg 3,3 38432 1763452 /sbin/init
mingetty 1632 root txt reg 3,3 14366 1763337 /sbin/mingetty
mingetty 1633 root txt reg 3,3 14366 1763337 /sbin/mingetty
mingetty 1634 root txt reg 3,3 14366 1763337 /sbin/mingetty
mingetty 1635 root txt reg 3,3 14366 1763337 /sbin/mingetty
mingetty 1636 root txt reg 3,3 14366 1763337 /sbin/mingetty
mingetty 1637 root txt reg 3,3 14366 1763337 /sbin/mingetty
kdm 1638 root txt reg 3,3 132548 1428194 /usr/bin/kdm
x 1670 root txt reg 3,3 1716396 1428336 /usr/bin/xorg
kdm 1671 root txt reg 3,3 132548 1428194 /usr/bin/kdm
startkde 2427 root txt reg 3,3 645408 1544195 /bin/bash
查找誰在使用檔案系統
# lsof /gtes11/
bash 4208 root cwd dir 3,1 4096 2 /gtes11/
vim 4230 root cwd dir 3,1 4096 2 /gtes11/
在這個示例中,使用者root正在其/gtes11目錄中進行一些操作。一個 bash是執行個體正在運作,并且它目前的目錄為/gtes11,另一個則顯示的是vim正在編輯/gtes11下的檔案。要成功地解除安裝/gtes11,應該在通知使用者以確定情況正常之後,中止這些程序。 這個示例說明了應用程式的目前工作目錄非常重要,因為它仍保持着檔案資源,并且可以防止檔案系統被解除安裝。這就是為什麼大部分守護程序(背景程序)将它們的目錄更改為根目錄、或服務特定的目錄(如 sendmail 示例中的 /var/spool/mqueue)的原因,以避免該守護程序阻止解除安裝不相關的檔案系統。
搜尋打開的網絡連接配接
如果想搜尋ip位址為10.645.64.23的遠端連接配接主機的所有網絡連接配接,可以執行如下指令,該指令可以打開系統中該遠端知己所有打開的套接字。:
/usr/sbin/lsof –[email protected]
尋找本地斷開的打開檔案
使用者經常遇到這種情況,當一個程序正在向一個檔案寫資料時,該檔案的目錄可能被移動。這就産生了一個非常大的問題。例如,使用者可能發現正在向/data寫資料,但是卻看不到檔案增大,lsof這個工具可以找到到這樣的錯誤
/usr/sbin/lsof –a +l1 /data
搜尋被程式打開的所有檔案及打開的檔案相關聯程序
如果想知道執行pid号為637的sendmail指令打開的所有檔案、裝置、庫及套接字等,可以執行
lsof -p 637
c 顯示出以字母 c開頭程序現在打開的檔案
例:顯示以init程序現在打開的檔案
# lsof -c init
command pid user fd type device size/off inode name
init 1 root cwd vdir 4095,365376 8192 2 /
init 1 root txt vreg 4095,365376 286720 463 /sbin/init
login name(登入名稱)或uid所正在打開檔案。
# lsof -u loginname
恢複删除的檔案
當程序打開了某個檔案時,隻要該程序保持打開該檔案,即使将其删除,它依然存在于磁盤中。這意味着,程序并不知道檔案已經被删除,它仍然可以向打開該檔案 時提供給它的檔案描述符進行讀取和寫入。除了該程序之外,這個檔案是不可見的,因為已經删除了其相應的目錄索引節點。
在/proc 目錄下,其中包含了反映核心和程序樹的各種檔案。/proc目錄挂載的是在記憶體中所映射的一塊區域,是以這些檔案和目錄并不存在于磁盤中,是以當我們對這 些檔案進行讀取和寫入時,實際上是在從記憶體中擷取相關資訊。大多數與 lsof 相關的資訊都存儲于以程序的 pid 命名的目錄中,即 /proc/1234 中包含的是 pid 為 1234 的程序的資訊。每個程序目錄中存在着各種檔案,它們可以使得應用程式簡單地了解程序的記憶體空間、檔案描述符清單、指向磁盤上的檔案的符号連結和其他系統信 息。lsof 程式使用該資訊和其他關于核心内部狀态的資訊來産生其輸出。是以lsof 可以顯示程序的檔案描述符和相關的檔案名等資訊。也就是我們通過通路程序的檔案描述符可以找到該檔案的相關資訊。
當系統中的某個檔案被意外地删除了,隻要這個時候系統中還有程序正在通路該檔案,那麼我們就可以通過lsof從/proc目錄下恢複該檔案的内容。 假如由于誤操作将/var/log/messages檔案删除掉了,那麼這時要将/var/log/messages檔案恢複的方法如下:
首先使用lsof來檢視目前是否有程序打開/var/logmessages檔案,如下:
# lsof |grep /var/log/messages
syslogd 1283 root 2w reg 3,3 5381017 1773647 /var/log/messages (deleted)
從上面的資訊可以看到 pid 1283(syslogd)打開檔案的檔案描述符為 2。同時還可以看到/var/log/messages已經标記被删除了。是以我們可以在 /proc/1283/fd/2 (fd下的每個以數字命名的檔案表示程序對應的檔案描述符)中檢視相應的資訊,如下:
# head -n 10 /proc/1283/fd/2
aug 4 13:50:15 holmes86 syslogd 1.4.1: restart.
aug 4 13:50:15 holmes86 kernel: klogd 1.4.1, log source = /proc/kmsg started.
aug 4 13:50:15 holmes86 kernel: bios-provided physical ram map:
aug 4 13:50:15 holmes86 kernel: bios-e820: 0000000000000000 - 000000000009f000 (usable)
aug 4 13:50:15 holmes86 kernel: bios-e820: 000000000009f000 - 00000000000a0000 (reserved)
aug 4 13:50:15 holmes86 kernel: bios-e820: 0000000000100000 - 000000001f7d3800 (usable)
aug 4 13:50:15 holmes86 kernel: bios-e820: 000000001f7d3800 - 0000000020000000 (reserved)
aug 4 13:50:15 holmes86 kernel: bios-e820: 00000000e0000000 - 00000000f0007000 (reserved)
aug 4 13:50:15 holmes86 kernel: bios-e820: 00000000f0008000 - 00000000f000c000 (reserved)
從上面的資訊可以看出,檢視 /proc/8663/fd/15 就可以得到所要恢複的資料。如果可以通過檔案描述符檢視相應的資料,那麼就可以使用 i/o 重定向将其複制到檔案中,如:
cat /proc/1283/fd/2 > /var/log/messages
對于許多應用程式,尤其是日志檔案和資料庫,這種恢複删除檔案的方法非常有用。
在 solaris 中查找删除的檔案
# lsof -a -p 8663 -d ^txt
command pid user fd type device size/off node name
httpd 8663 nobody cwd vdir 136,8 1024 2 /
httpd 8663 nobody 0r vchr 13,2 6815752 /devices/pseudo/mm@0:null
httpd 8663 nobody 1w vchr 13,2 6815752 /devices/pseudo/mm@0:null
httpd 8663 nobody 2w vreg 136,8 185 145465 / (/dev/dsk/c0t0d0s0)
httpd 8663 nobody 4r door 0t0 58 /var/run/name_service_door
(door to nscd[81]) (fa:->0x30002b156c0)
httpd 8663 nobody 15w vreg 136,8 185 145465 / (/dev/dsk/c0t0d0s0)
httpd 8663 nobody 16u ipv4 0x300046d27c0 0t0 tcp *:80 (listen)
httpd 8663 nobody 17w vreg 136,8 0 145466 /var/apache/logs/access_log
httpd 8663 nobody 18w vreg 281,3 0 9518013 /var/run (swap)
使用 -a 和 -d 參數對輸出進行篩選,以排除代碼程式段,"^"是取反的意思。name 列顯示出,其中的兩個檔案(fd 2 和 15)使用磁盤名代替了檔案名,并且它們的類型為 vreg(正常檔案)。在 solaris 中,删除的檔案将顯示檔案所在的磁盤的名稱。通過這個線索,就可以知道該 fd 指向一個删除的檔案。實際上,檢視 /proc/8663/fd/15 就可以得到所要查找的資料。
linux lsof 修改句柄限制
# lsof -n|awk '{print $2}'|sort|uniq -c |sort -nr|more
131 24204
57 24244
57 24231
56 24264
其中第一列是打開的檔案句柄數量,第二行是程序号。得到程序号後,我們可以通過ps指令得到程序的詳細内容。
#ps -aef|grep 24204
mysql 24204 24162 99 16:15 ? 00:24:25 /usr/sbin/mysqld
檢視得知是mysql程序打開最多檔案句柄數量。但是他目前隻打開了131個檔案句柄數量,遠遠底于系統預設值1024。
但是如果系統并發特别大,尤其是squid伺服器,很有可能會超過1024。這時候就必須要調整系統參數,以适應應用變化。linux關于打開檔案句柄數量,有硬性限制和軟性限制。可以通過ulimit來設定這兩個參數。方法如下,以root使用者運作以下指令:
#ulimit -hsn 4096
以上指令中,h指定了硬性大小,s指定了軟性大小,n表示設定單個程序最大的打開檔案句柄數量。個人覺得最好不要超過4096,畢竟打開的檔案句柄數越多 響應時間肯定會越慢。設定句柄數量後,系統重新開機後,又會恢複預設值。如果想永久儲存下來,可以修改 /etc/profile 把上面指令加到最後。
參考至:http://hi.baidu.com/angel_dbi/item/cd2b35eac71920f62b09a4f9
http://www.cnblogs.com/rootq/articles/1401850.html
http://www.ibm.com/developerworks/cn/aix/library/au-lsof.html
本文原創,轉載請注明出處、作者
如有錯誤,歡迎指正
作者:czmmiao 文章出處:http://czmmiao.iteye.com/blog/1734384