經過查看打開的文件,瞭解更多關於系統的信息。瞭解應用程序打開了哪些文件或者哪一個應用程序打開了特定的文件,做爲系統管理員,這將使得您可以做出更好的決策。例如,您不該該卸載具備打開文件的文件系統。使用 lsof
,您能夠檢查打開的文件,並根據須要在卸載以前停止相應的進程。一樣地,若是您發現了一個未知的文件,那麼能夠找出究竟是哪一個應用程序打開了這個文件。html
在 UNIX 環境中,文件無處不在,這便產生了一句格言:「任何事物都是文件」。經過文件不只僅能夠訪問常規數據,一般還能夠訪問網絡鏈接和硬件。在有些狀況下,當您使用 ls
請求目錄清單時,將出現相應的條目。在其餘狀況下,如傳輸控制協議 (TCP) 和用戶數據報協議 (UDP) 套接字,不存在相應的目錄清單。可是在後臺爲該應用程序分配了一個文件描述符,不管這個文件的本質如何,該文件描述符爲應用程序與基礎操做系統之間的交互提供了通用接口。linux
由於應用程序打開文件的描述符列表提供了大量關於這個應用程序自己的信息,因此可以查看這個列表將是頗有幫助的。完成這項任務的實用程序稱爲 lsof
,它對應於「list open files」(列出打開的文件)。幾乎在每一個 UNIX 版本中都有這個實用程序,但奇怪的是,大多數供應商並無將其包含在操做系統的初始安裝中。要獲取更多關於 lsof
的信息,請參見參考資料部分。數據庫
只需輸入 lsof
就能夠生成大量的信息,如清單 1 所示。由於 lsof
須要訪問核心內存和各類文件,因此必須以 root 用戶的身份運行它纔可以充分地發揮其功能。apache
bash-3.00# lsof COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sched 0 root cwd VDIR 136,8 1024 2 / init 1 root cwd VDIR 136,8 1024 2 / init 1 root txt VREG 136,8 49016 1655 /sbin/init init 1 root txt VREG 136,8 51084 3185 /lib/libuutil.so.1 vi 2013 root 3u VREG 136,8 0 8501 /var/tmp/ExXDaO7d ...
每行顯示一個打開的文件,除非另外指定,不然將顯示全部進程打開的全部文件。Command
、PID
和 User
列分別表示進程的名稱、進程標識符 (PID) 和全部者名稱。Device
、SIZE/OFF
、Node
和 Name
列涉及到文件自己的信息,分別表示指定磁盤的名稱、文件的大小、索引節點(文件在磁盤上的標識)和該文件的確切名稱。根據 UNIX 版本的不一樣,可能將文件的大小報告爲應用程序在文件中進行讀取的當前位置(偏移量)。清單 1 來自一臺能夠報告該信息的 Sun Solaris 10 計算機,而 Linux 沒有這個功能。bash
FD
和 Type
列的含義最爲模糊,它們提供了關於文件如何使用的更多信息。FD
列表示文件描述符,應用程序經過文件描述符識別該文件。Type
列提供了關於文件格式的更多描述。咱們來具體研究一下文件描述符列,清單 1 中出現了三種不一樣的值。cwd
值表示應用程序的當前工做目錄,這是該應用程序啓動的目錄,除非它自己對這個目錄進行更改。txt
類型的文件是程序代碼,如應用程序二進制文件自己或共享庫,再好比本示例的列表中顯示的 init
程序。最後,數值表示應用程序的文件描述符,這是打開該文件時返回的一個整數。在清單 1 輸出的最後一行中,您能夠看到用戶正在使用 vi
編輯 /var/tmp/ExXDaO7d,其文件描述符爲 3。u
表示該文件被打開並處於讀取/寫入模式,而不是隻讀 (r
) 或只寫 (w
) 模式。有一點不是很重要但卻頗有幫助,初始打開每一個應用程序時,都具備三個文件描述符,從 0 到 2,分別表示標準輸入、輸出和錯誤流。正由於如此,大多數應用程序所打開的文件的 FD 都是從 3 開始。網絡
與 FD
列相比,Type
列則比較直觀。根據具體操做系統的不一樣,您會發現將文件和目錄稱爲 REG
和 DIR
(在 Solaris 中,稱爲 VREG
和VDIR
)。其餘可能的取值爲 CHR
和 BLK
,分別表示字符和塊設備;或者 UNIX
、FIFO
和 IPv4
,分別表示 UNIX 域套接字、先進先出 (FIFO) 隊列和網際協議 (IP) 套接字。ssh
儘管與使用 lsof
沒有什麼直接的關係,但對 /proc 目錄進行簡要的介紹是有必要的。/proc 是一個目錄,其中包含了反映內核和進程樹的各類文件。這些文件和目錄並不存在於磁盤中,所以當您對這些文件進行讀取和寫入時,其實是在從操做系統自己獲取相關信息。大多數與 lsof
相關的信息都存儲於以進程的 PID 命名的目錄中,因此 /proc/1234 中包含的是 PID 爲 1234 的進程的信息。ide
在 /proc 目錄的每一個進程目錄中存在着各類文件,它們可使得應用程序簡單地瞭解進程的內存空間、文件描述符列表、指向磁盤上的文件的符號連接和其餘系統信息。lsof
實用程序使用該信息和其餘關於內核內部狀態的信息來產生其輸出。稍後我將把 lsof
的輸出與 /proc 目錄中的信息聯繫起來。工具
前面,我向您介紹瞭如何簡單地運行不帶任何參數的 lsof
,以便顯示關於每一個進程所打開的文件的信息。本文餘下的部分將重點關注如何使用lsof
來顯示所需的信息以及如何正確地對其進行解釋。ui
lsof
常見的用法是查找應用程序打開的文件的名稱和數目。您可能想嘗試找出某個特定應用程序將日誌數據記錄到何處,或者正在跟蹤某個問題。例如,UNIX 限制了進程可以打開文件的數目。一般這個數值很大,因此不會產生問題,而且在須要時,應用程序能夠請求更大的值(直到某個上限)。若是您懷疑應用程序耗盡了文件描述符,那麼可使用 lsof
統計打開的文件數目,以進行驗證。
要指定單個進程,可使用 -p
參數,後面加上該進程的 PID。由於這樣作不只會返回該應用程序所打開的文件,還會返回共享庫和代碼,因此一般須要對輸出進行篩選。要完成此任務,可使用 -d
標誌根據 FD
列進行篩選,使用 -a
標誌表示兩個參數都必須知足 (AND)。若是沒有 -a
標誌,缺省的狀況是顯示匹配任何一個參數 (OR) 的文件。清單 2 顯示了 sendmail
進程打開的文件,並使用 txt 對這些文件進行篩選。
sh-3.00# lsof -a -p 605 -d ^txt COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sendmail 605 root cwd VDIR 136,8 1024 23554 /var/spool/mqueue sendmail 605 root 0r VCHR 13,2 6815752 /devices/pseudo/mm@0:null sendmail 605 root 1w VCHR 13,2 6815752 /devices/pseudo/mm@0:null sendmail 605 root 2w VCHR 13,2 6815752 /devices/pseudo/mm@0:null sendmail 605 root 3r DOOR 0t0 58 /var/run/name_service_door(door to nscd[81]) (FA:->0x30002b156c0) sendmail 605 root 4w VCHR 21,0 11010052 /devices/pseudo/log@0:conslog->LOG sendmail 605 root 5u IPv4 0x300010ea640 0t0 TCP *:smtp (LISTEN) sendmail 605 root 6u IPv6 0x3000431c180 0t0 TCP *:smtp (LISTEN) sendmail 605 root 7u IPv4 0x300046d39c0 0t0 TCP *:submission (LISTEN) sendmail 605 root 8wW VREG 281,3 32 8778600 /var/run/sendmail.pid
清單 2 爲 lsof
指定了三個參數。第一個是 -a
,它表示當全部的參數都爲真時,才顯示這個文件。第二個參數是 -p 605
,它限制僅輸出 PID 爲 605 的進程,能夠經過 ps
命令獲取這個信息。最後一個參數 -d ^txt
,它表示篩選出其中 txt 類型的記錄(脫字符號 [^] 表示排除)。
清單 2 的輸出提供了關於進程行爲的信息。如 cwd
行所示,該應用程序的工做目錄爲 /var/spool/mqueue。文件描述符 0、1 和 2 分配給了 /dev/null(Solaris 大量使用符號連接,因此這裏顯示了相應的僞設備)。FD 3 是一個 Solaris 門(高速遠程過程調用 (RPC) 接口),以只讀模式打開。FD 4 中的內容比較有趣,由於它是一個字符設備的只讀句柄,實質上是 /dev/log。從這個文件中,您能夠收集該應用程序向 UNIX syslog 守護進程進行的記錄,因此 /etc/syslog.conf 規定了日誌文件的位置。
做爲一個網絡應用程序,sendmail
對網絡端口進行監聽。文件描述符 五、6 和 7 能夠告訴您,該應用程序正以 IPv4 和 IPv6 模式監聽簡單郵件傳輸協議 (SMTP) 端口,並以 IPv4 模式監聽提交端口。最後一個文件描述符是隻寫的,而且指向 /var/run/sendmail.pid。FD
列中的大寫 W
表示該應用程序具備對整個文件的寫鎖。該文件用於確保每次只能打開一個應用程序實例。
在其餘狀況下,您有一個文件或目錄,而且須要知道哪一個應用程序控制了該文件(打開了該文件)。清單 2 顯示了由 sendmail
進程打開了 /var/run/sendmail.pid。若是您不知道這個信息,那麼在給定文件名的狀況下,lsof
能夠提供該信息。清單 3 顯示了相應的輸出。
bash-3.00# lsof /var/run/sendmail.pid COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sendmail 605 root 8wW VREG 281,3 32 8778600 /var/run/sendmail.pid
正如輸出所示,進程 sendmail
(PID 爲 605)控制了文件 /var/run/sendmail.pid,而且經過排它鎖打開該文件以便進行寫入。若是出於某種緣由,您須要刪除這個文件,那麼正確的作法是停止該進程,而不是直接刪除這個文件。不然,這個守護進程下次可能沒法正常啓動,或者可能稍後會啓動另外一個實例,從而致使爭用。
有時您只知道在文件系統的某處打開了文件。在卸載文件系統時,若是該文件系統中有任何打開的文件,那麼操做將會失敗。經過指定裝入點的名稱,您可使用 lsof
顯示一個文件系統中全部打開的文件。清單 4 顯示瞭如未嘗試卸載 /export/home,而後使用 lsof
找出誰在使用該文件系統。
bash-3.00# umount /export/home umount: /export/home busy bash-3.00# lsof /export/home COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME bash 1943 root cwd VDIR 136,7 1024 4 /export/home/sean bash 2970 sean cwd VDIR 136,7 1024 4 /export/home/sean ct 3030 sean cwd VDIR 136,7 1024 4 /export/home/sean ct 3030 sean 1w VREG 136,7 0 25 /export/home/sean/output
在這個示例中,用戶 sean 正在其 home 目錄中進行一些操做。有兩個 bash
(一種 Shell)實例正在運行,而且當前目錄設置爲 sean 的 home 目錄。還有一個名爲 ct
的應用程序正運行於相同的目錄,而且其標準輸出(文件描述符 1)重定向到一個名爲 output 的文件。要成功地卸載 /export/home,應該在通知用戶以確保狀況正常以後,停止這些進程。
這個示例說明了應用程序的當前工做目錄很是重要,由於它仍保持着文件資源,而且能夠防止文件系統被卸載。這就是爲何大部分守護進程(後臺進程)將它們的目錄更改成根目錄、或服務特定的目錄(如 sendmail
示例中的 /var/spool/mqueue)的緣由,以免該守護進程阻止卸載不相關的文件系統。若是 sendmail
從 /export/home/sean 目錄啓動,而且沒有將其目錄更改成 /var/spool/mqueue,那麼在卸載 /export/home 前必須停止它。
若是您對非裝入點目錄中打開的文件感興趣,那麼必須經過 +d
或 +D
指定該目錄的名稱,具體使用其中的哪個標誌取決於您須要遞歸到子目錄(+D
)或者不須要遞歸到子目錄(+d
)。例如,要查看 /export/home/sean 中全部打開的文件,可使用 lsof +D /export/home/sean
。在前面的示例中,相關的目錄是一個裝入點,而這裏與前面的示例存在細微的差異,而且限制了 lsof
和內核之間的交互。這還會引發潛在的問題,即 lsof /export/home
與 lsof /export/home/
(請注意尾部的斜槓)有所區別。第一種方式能夠正常工做,由於它指向了裝入點。第二種方式不會生成任何輸出,由於它指向了目錄。若是您在 Shell 中使用 Tab 鍵自動完成命令,那麼可能碰到這個問題,其中會幫助您添加結尾的斜槓。在這種狀況下,您能夠刪除這個斜槓或者使用 +D
指定目錄。前者是首選的方法,由於與指定任意的目錄相比,其執行速度更快。
在前面的部分中,咱們研究了 lsof
的基本用法,即顯示打開的文件和控制它們的進程之間的關係。當您想對系統進行一些煩瑣的操做,而又不但願破壞別人重要的文檔時,這種方法頗有幫助。您還可使用相同的方法執行一些高難度的 UNIX 操做。
當 UNIX 計算機受到***時,常見的狀況是日誌文件被刪除,以掩蓋***者的蹤影。管理錯誤也可能致使意外刪除重要的文件,好比在清理舊日誌時,意外地刪除了數據庫的活動事務日誌。有時能夠恢復這些文件,而且 lsof
能夠爲您提供幫助。
當進程打開了某個文件時,只要該進程保持打開該文件,即便將其刪除,它依然存在於磁盤中。這意味着,進程並不知道文件已經被刪除,它仍然能夠向打開該文件時提供給它的文件描述符進行讀取和寫入。除了該進程以外,這個文件是不可見的,由於已經刪除了其相應的目錄條目。
前面曾在轉到 /proc 目錄部分中說過,經過在適當的目錄中進行查找,您能夠訪問進程的文件描述符。在隨後的內容中,您看到了 lsof
能夠顯示進程的文件描述符和相關的文件名。您能明白個人意思嗎?
希望它真的這麼簡單!當您向 lsof
傳遞文件名時,好比在 lsof /file/I/deleted
中,它首先使用 stat()
系統調用得到有關該文件的信息,不幸的是,這個文件已經被刪除。在不一樣的操做系統中,lsof
可能能夠從核心內存中捕獲該文件的名稱。清單 5 顯示了一個 Linux 系統,其中意外地刪除了 Apache 日誌,我正使用 grep
工具查找是否有人打開了該文件。
# lsof | grep error_log httpd 2452 root 2w REG 33,2 499 3090660 /var/log/httpd/error_log (deleted) httpd 2452 root 7w REG 33,2 499 3090660 /var/log/httpd/error_log (deleted) ... more httpd processes ...
在這個示例中,您能夠看到 PID 2452 打開文件的文件描述符爲 2(標準錯誤)和 7。所以,能夠在 /proc/2452/fd/7 中查看相應的信息,如清單 6 所示。
# cat /proc/2452/fd/7 [Sun Apr 30 04:02:48 2006] [notice] Digest: generating secret for digest authentication [Sun Apr 30 04:02:48 2006] [notice] Digest: done [Sun Apr 30 04:02:48 2006] [notice] LDAP: Built with OpenLDAP LDAP SDK
Linux 的優勢在於,它保存了文件的名稱,甚至能夠告訴咱們它已經被刪除。在遭到破壞的系統中查找相關內容時,這是很是有用的內容,由於***者一般會刪除日誌以隱藏他們的蹤影。Solaris 並不提供這些信息。然而,咱們知道 httpd
守護進程使用了 error_log 文件,因此可使用ps
命令找到這個 PID,而後能夠查看這個守護進程打開的全部文件。
# 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
就能夠獲得所要查找的數據。
若是能夠經過文件描述符查看相應的數據,那麼您就可使用 I/O 重定向將其複製到文件中,如 cat /proc/8663/fd/15 > /tmp/error_log
。此時,您能夠停止該守護進程(這將刪除 FD,從而刪除相應的文件),將這個臨時文件複製到所需的位置,而後從新啓動該守護進程。
對於許多應用程序,尤爲是日誌文件和數據庫,這種恢復刪除文件的方法很是有用。正如您所看到的,有些操做系統(以及不一樣版本的 lsof
)比其餘的系統更容易查找相應的數據。
網絡鏈接也是文件,這意味着可使用 lsof
得到關於它們的信息。您曾在清單 2 中看到過這樣的示例。該示例假設您已經知道 PID,可是有時候並不是如此。若是您只知道相應的端口,那麼可使用 -i
參數利用套接字信息進行搜索。清單 8 顯示了對 TCP 端口 25 的搜索。
# lsof -i :25 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sendmail 605 root 5u IPv4 0x300010ea640 0t0 TCP *:smtp (LISTEN) sendmail 605 root 6u IPv6 0x3000431c180 0t0 TCP *:smtp (LISTEN)
須要以 protocol:@ip:port
的形式向 lsof
實用程序傳遞相關信息,其中的 protocol 爲 TCP 或 UDP(可使用 4 或 6 做爲前綴,表示 IP 的版本),IP 爲可解析的名稱或 IP 地址,而 port 爲數字或表示該服務的名稱(來自 /etc/services)。須要一個或多個元素(端口、IP、協議)。在清單 8 中,:25
表示端口 25。輸出顯示,進程 605 正在使用 IPv6 和 IPv4 監聽端口 25。若是您對 IPv4 不感興趣,那麼能夠將篩選器改成 6:25
,以表示監聽端口 25 的 IPv6 套接字,或者直接使用 6
表示全部的 IPv6 鏈接。
除了顯示出這些守護進程正在監聽的對象,lsof
還能夠發現發生的鏈接,一樣是使用 -i
參數。清單 9 顯示了搜索與 192.168.1.10 之間的全部鏈接。
# lsof -i @192.168.1.10 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sshd 1934 root 6u IPv6 0x300046d21c0 0t1303608 TCP sun:ssh->linux:40379 (ESTABLISHED) sshd 1937 root 4u IPv6 0x300046d21c0 0t1303608 TCP sun:ssh->linux:40379 (ESTABLISHED)
在這個示例中,sun
和 linux
之間有兩個 IPv6 鏈接。對其進行更仔細的研究能夠看出,這些鏈接來自於兩個不一樣的進程,但它們倒是相同的,這是由於兩臺主機是相同的,而且端口也是相同的(ssh 和 40379)。這是因爲進入主進程的鏈接分叉出一個處理程序,並將該套接字傳遞給它。您還能夠看到,名爲 sun
的計算機正在使用端口 22 (ssh),而 linux
具備端口 40379。這表示,sun
是該鏈接的接收者,由於它關聯於該服務的已知端口。40379 是源或臨時端口,而且僅對這個鏈接有意義。
由於,至少在 UNIX 中,套接字是另外一類文件,因此 lsof
能夠得到關於這些鏈接的詳細信息,並找出誰對它們負責。
UNIX 大量使用了文件。做爲系統管理員,lsof
容許您對核心內存進行查看,以找出系統當前如何使用這些文件。lsof
最簡單的用法能夠告訴您哪些進程打開了哪些文件,以及哪些文件由哪些進程打開。在收集關於應用程序工做狀況的信息時,或在進行某些可能損壞數據的操做前確保文件未被使用時,這一點特別重要lsof
更高級的用法能夠幫助您查找刪除的文件,並得到關於網絡鏈接的信息。這是一個功能強大的工具,它幾乎能夠用於任何地方。
補充:
FD 列中的文件描述符cwd 值表示應用程序的當前工做目錄,這是該應用程序啓動的目錄,除非它自己對這個目錄進行更改,txt 類型的文件是程序代碼,如應用程序二進制文件自己或共享庫,如上列表中顯示的 /sbin/init 程序。
其次數值表示應用程序的文件描述符,這是打開該文件時返回的一個整數。如上的最後一行文件/dev/initctl,其文件描述符爲 10。u 表示該文件被打開並處於讀取/寫入模式,而不是隻讀 或只寫 (w) 模式。同時還有大寫 的W 表示該應用程序具備對整個文件的寫鎖。該文件描述符用於確保每次只能打開一個應用程序實例。初始打開每一個應用程序時,都具備三個文件描述符,從 0 到 2,分別表示標準輸入、輸出和錯誤流。因此大多數應用程序所打開的文件的 FD 都是從 3 開始。
與 FD 列相比,Type 列則比較直觀。文件和目錄分別稱爲 REG 和 DIR。而CHR 和 BLK,分別表示字符和塊設備;或者 UNIX、FIFO 和 IPv4,分別表示 UNIX 域套接字、先進先出 (FIFO) 隊列和網際協議 (IP) 套接字。
文章來源:http://www.ibm.com/developerworks/cn/aix/library/au-lsof.html