linux/unix lsof用法

來源:互聯網
上載者:User

標籤:des   http   io   使用   ar   for   檔案   資料   div   

使用 lsof 尋找開啟的檔案

通過查看開啟的檔案,瞭解更多關於系統的資訊。瞭解應用程式開啟了哪些檔案或者哪個應用程式開啟了特定的檔案,作為系統管理員,這將使得您能夠作出更好的決策。例如,您不應該卸載具有開啟檔案的檔案系統。使用 lsof,您可以檢查開啟的檔案,並根據需要在卸載之前中止相應的進程。同樣地,如果您發現了一個未知的檔案,那麼可以找出到底是哪個應用程式開啟了這個檔案。

在 UNIX® 環境中,檔案無處不在,這便產生了一句格言:“任何事物都是檔案”。通過檔案不僅僅可以訪問常規資料,通常還可以訪問網路連接和硬體。在有些情況下,當您使用 ls 請求目錄清單時,將出現相應的條目。在其他情況下,如傳輸控制通訊協定 (TCP) 和使用者資料包通訊協定 (UDP) 通訊端,不存在相應的目錄清單。但是在後台為該應用程式分配了一個檔案描述符,無論這個檔案的本質如何,該檔案描述符為應用程式與基礎作業系統之間的互動提供了通用介面。

因為應用程式開啟檔案的描述符列表提供了大量關於這個應用程式本身的資訊,所以能夠查看這個列表將是很有協助的。完成這項任務的公用程式稱為 lsof,它對應於“list open files”(列出開啟的檔案)。幾乎在每個 UNIX 版本中都有這個公用程式,但奇怪的是,大多數供應商並沒有將其包含在作業系統的初始安裝中。要擷取更多關於 lsof 的資訊,請參見參考資料部分。

lsof 簡介

只需輸入 lsof 就可以產生大量的資訊,如清單 1 所示。因為 lsof 需要訪問核心記憶體和各種檔案,所以必須以 root 使用者的身份運行它才能夠充分地發揮其功能。

清單 1. lsof 的樣本輸出
bash-3.00# lsof COMMAND    PID   USER   FD   TYPE        DEVICE SIZE/OFF      NODE NAMEsched        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/initinit         1   root  txt   VREG         136,8    51084      3185 /lib/libuutil.so.1vi        2013   root    3u  VREG         136,8        0      8501 /var/tmp/ExXDaO7d...

每行顯示一個開啟的檔案,除非另外指定,否則將顯示所有進程開啟的所有檔案。CommandPIDUser 列分別表示進程的名稱、進程標識符 (PID) 和所有者名稱。DeviceSIZE/OFFNodeName 列涉及到檔案本身的資訊,分別表示指定磁碟的名稱、檔案的大小、索引節點(檔案在磁碟上的標識)和該檔案的確切名稱。根據 UNIX 版本的不同,可能將檔案的大小報告為應用程式在檔案中進行讀取的當前位置(位移量)。清單 1 來自一台可以報告該資訊的 Sun Solaris 10 電腦,而 Linux® 沒有這個功能。

FDType 列的含義最為模糊,它們提供了關於檔案如何使用的更多資訊。FD 列表示檔案描述符,應用程式通過檔案描述符識別該檔案。Type 列提供了關於檔案格式的更多描述。我們來具體研究一下檔案描述符列,清單 1 中出現了三種不同的值。cwd 值表示應用程式的當前工作目錄,這是該應用程式啟動的目錄,除非它本身對這個目錄變更。txt 類型的檔案是程式碼,如應用程式二進位檔案本身或共用庫,再比如本樣本的列表中顯示的 init 程式。最後,數值表示應用程式的檔案描述符,這是開啟該檔案時返回的一個整數。在清單 1 輸出的最後一行中,您可以看到使用者正在使用 vi 編輯 /var/tmp/ExXDaO7d,其檔案描述符為 3。u 表示該檔案被開啟並處於讀取/寫入模式,而不是唯讀 (r) 或唯寫 (w) 模式。有一點不是很重要但卻很有協助,初始開啟每個應用程式時,都具有三個檔案描述符,從 0 到 2,分別表示標準輸入、輸出和錯誤流。正因為如此,大多數應用程式所開啟的檔案的 FD 都是從 3 開始。

FD 列相比,Type 列則比較直觀。根據具體作業系統的不同,您會發現將檔案和目錄稱為 REGDIR(在 Solaris 中,稱為 VREGVDIR)。其他可能的取值為 CHRBLK,分別表示字元和塊裝置;或者 UNIXFIFOIPv4,分別表示 UNIX 域通訊端、先進先出 (FIFO) 隊列和網際協議 (IP) 通訊端。

轉到 /proc 目錄

儘管與使用 lsof 沒有什麼直接的關係,但對 /proc 目錄進行簡要的介紹是有必要的。/proc 是一個目錄,其中包含了反映核心和進程樹的各種檔案。這些檔案和目錄並不存在於磁碟中,因此當您對這些檔案進行讀取和寫入時,實際上是在從作業系統本身擷取相關資訊。大多數與 lsof 相關的資訊都儲存於以進程的 PID 命名的目錄中,所以 /proc/1234 中包含的是 PID 為 1234 的進程的資訊。

在 /proc 目錄的每個進程目錄中存在著各種檔案,它們可以使得應用程式簡單地瞭解進程的記憶體空間、檔案描述符列表、指向磁碟上的檔案的符號連結和其他系統資訊。lsof 公用程式使用該資訊和其他關於核心內部狀態的資訊來產生其輸出。稍後我將把 lsof 的輸出與 /proc 目錄中的資訊聯絡起來。

常見用法

前面,我向您介紹了如何簡單地運行不帶任何參數的 lsof,以便顯示關於每個進程所開啟的檔案的資訊。本文餘下的部分將重點關注如何使用 lsof 來顯示所需的資訊以及如何正確地對其進行解釋。

尋找應用程式開啟的檔案

lsof 常見的用法是尋找應用程式開啟的檔案的名稱和數目。您可能想嘗試找出某個特定應用程式將日誌資料記錄到何處,或者正在跟蹤某個問題。例如,UNIX 限制了進程能夠開啟檔案的數目。通常這個數值很大,所以不會產生問題,並且在需要時,應用程式可以請求更大的值(直到某個上限)。如果您懷疑應用程式耗盡 了檔案描述符,那麼可以使用 lsof 統計開啟的檔案數目,以進行驗證。

要指定單個進程,可以使用 -p 參數,後面加上該進程的 PID。因為這樣做不僅會返回該應用程式所開啟的檔案,還會返回共用庫和代碼,所以通常需要對輸出進行篩選。要完成此任務,可以使用 -d 標誌根據 FD 列進行篩選,使用 -a 標誌表示兩個參數都必須滿足 (AND)。如果沒有 -a 標誌,預設的情況是顯示匹配任何一個參數 (OR) 的檔案。清單 2 顯示了 sendmail 進程開啟的檔案,並使用 txt 對這些檔案進行篩選。

清單 2. 帶有 PID 篩選器並進行 txt 檔案描述符篩選的 lsof 輸出
sh-3.00# lsof -a -p 605 -d ^txtCOMMAND  PID USER   FD   TYPE  DEVICE SIZE/OFF     NODE NAMEsendmail 605 root  cwd   VDIR  136,8     1024    23554 /var/spool/mqueuesendmail 605 root    0r  VCHR  13,2            6815752 /devices/pseudo/[email protected]:nullsendmail 605 root    1w  VCHR  13,2            6815752 /devices/pseudo/[email protected]:nullsendmail 605 root    2w  VCHR  13,2            6815752 /devices/pseudo/[email protected]:nullsendmail 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/[email protected]:conslog->LOGsendmail 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 對網路連接埠進行監聽。檔案描述符 5、6 和 7 可以告訴您,該應用程式正以 IPv4 和 IPv6 模式監聽簡易郵件傳輸通訊協定 (SMTP) 連接埠,並以 IPv4 模式監聽提交連接埠。最後一個檔案描述符是唯寫的,並且指向 /var/run/sendmail.pid。FD 列中的大寫 W 表示該應用程式具有對整個檔案的寫鎖。該檔案用於確保每次只能開啟一個應用程式執行個體。

尋找開啟某個檔案的應用程式

在其他情況下,您有一個檔案或目錄,並且需要知道哪個應用程式控制了該檔案(開啟了該檔案)。清單 2 顯示了由 sendmail 進程開啟了 /var/run/sendmail.pid。如果您不知道這個資訊,那麼在給定檔案名稱的情況下,lsof 可以提供該資訊。清單 3 顯示了相應的輸出。

清單 3. 要求 lsof 顯示關於某個檔案的資訊
bash-3.00# lsof /var/run/sendmail.pidCOMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAMEsendmail 605 root    8wW VREG  281,3       32 8778600 /var/run/sendmail.pid

正如輸出所示,進程 sendmail(PID 為 605)控制了檔案 /var/run/sendmail.pid,並且通過排它鎖開啟該檔案以便進行寫入。如果出於某種原因,您需要刪除這個檔案,那麼正確的做法是中止該進 程,而不是直接刪除這個檔案。否則,這個守護進程下次可能無法正常啟動,或者可能稍後會啟動另一個執行個體,從而導致爭用。

有時您只知道在檔案系統的某處開啟了檔案。在卸載檔案系統時,如果該檔案系統中有任何開啟的檔案,那麼操作將會失敗。通過指定掛接點的名稱,您可以使用 lsof 顯示一個檔案系統中所有開啟的檔案。清單 4 顯示了如何嘗試卸載 /export/home,然後使用 lsof 找出誰在使用該檔案系統。

清單 4. 使用 lsof 找出誰在使用檔案系統
bash-3.00# umount /export/homeumount: /export/home busybash-3.00# lsof /export/homeCOMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAMEbash    1943 root  cwd   VDIR  136,7     1024    4 /export/home/seanbash    2970 sean  cwd   VDIR  136,7     1024    4 /export/home/seanct      3030 sean  cwd   VDIR  136,7     1024    4 /export/home/seanct      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/homelsof /export/home/(請 注意尾部的斜杠)有所區別。第一種方式可以正常工作,因為它指向了掛接點。第二種方式不會產生任何輸出,因為它指向了目錄。如果您在 Shell 中使用 Tab 鍵自動完成命令,那麼可能碰到這個問題,其中會協助您添加結尾的斜杠。在這種情況下,您可以刪除這個斜杠或者使用 +D 指定目錄。前者是首選的方法,因為與指定任意的目錄相比,其執行速度更快。

不常見的用法

在前面的部分中,我們研究了 lsof 的基本用法,即顯示開啟的檔案和控制它們的進程之間的關係。當您想對系統進行一些煩瑣的操作,而又不希望破壞別人重要的文檔時,這種方法很有協助。您還可以使用相同的方法執行一些高難度的 UNIX 操作。

恢複刪除的檔案

當 UNIX 電腦受到入侵時,常見的情況是記錄檔被刪除,以掩蓋攻擊者的蹤跡。管理錯誤也可能導致意外刪除重要的檔案,比如在清理舊日誌時,意外地刪除了資料庫的活動交易記錄。有時可以恢複這些檔案,並且 lsof 可以為您提供協助。

當進程開啟了某個檔案時,只要該進程保持開啟該檔案,即使將其刪除,它依然存在於磁碟中。這意味著,進程並不知道檔案已經被刪除,它仍然可以向開啟該檔案時提供給它的檔案描述符進行讀取和寫入。除了該進程之外,這個檔案是不可見的,因為已經刪除了其相應的目錄條目。

前面曾在轉到 /proc 目錄部分中說過,通過在適當的目錄中進行尋找,您可以訪問進程的檔案描述符。在隨後的內容中,您看到了 lsof 可以顯示進程的檔案描述符和相關的檔案名稱。您能明白我的意思嗎?

但願它真的這麼簡單!當您向 lsof 傳遞檔案名稱時,比如在 lsof /file/I/deleted 中,它首先使用 stat() 系統調用獲得有關該檔案的資訊,不幸的是,這個檔案已經被刪除。在不同的作業系統中,lsof 可能可以從核心記憶體中捕獲該檔案的名稱。清單 5 顯示了一個 Linux 系統,其中意外地刪除了 Apache 日誌,我正使用 grep 工具尋找是否有人開啟了該檔案。

清單 5. 在 Linux 中使用 lsof 尋找刪除的檔案
# lsof | grep error_loghttpd      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 所示。

清單 6. 通過 /proc 尋找刪除的檔案
# 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,然後可以查看這個守護進程開啟的所有檔案。

清單 7. 在 Solaris 中尋找刪除的檔案
# lsof -a -p 8663 -d ^txtCOMMAND  PID   USER   FD   TYPE        DEVICE SIZE/OFF    NODE NAMEhttpd   8663 nobody  cwd   VDIR         136,8     1024       2 /httpd   8663 nobody    0r  VCHR          13,2          6815752 /devices/pseudo/[email protected]:nullhttpd   8663 nobody    1w  VCHR          13,2          6815752 /devices/pseudo/[email protected]:nullhttpd   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_loghttpd   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 的搜尋。

清單 8. 尋找監聽連接埠 25 的進程
# lsof -i :25COMMAND  PID USER   FD   TYPE        DEVICE SIZE/OFF NODE NAMEsendmail 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 之間的所有串連。

清單 9. 搜尋活動的串連
# lsof -i @192.168.1.10COMMAND  PID USER   FD   TYPE        DEVICE  SIZE/OFF NODE NAMEsshd    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)

在這個樣本中,sunlinux 之間有兩個 IPv6 串連。對其進行更仔細的研究可以看出,這些串連來自於兩個不同的進程,但它們卻是相同的,這是因為兩台主機是相同的,並且連接埠也是相同的(ssh 和 40379)。這是由於進入主進程的串連分叉出一個處理常式,並將該通訊端傳遞給它。您還可以看到,名為 sun 的電腦正在使用連接埠 22 (ssh),而 linux 具有連接埠 40379。這表示,sun 是該串連的接收者,因為它關聯於該服務的已知連接埠。40379 是源或臨時連接埠,並且僅對這個串連有意義。

因為,至少在 UNIX 中,通訊端是另一類檔案,所以 lsof 可以獲得關於這些串連的詳細資料,並找出誰對它們負責。

結束語

UNIX 大量使用了檔案。作為系統管理員,lsof 允許您對核心記憶體進行查看,以找出系統當前如何使用這些檔案。lsof 最簡單的用法可以告訴您哪些進程開啟了哪些檔案,以及哪些檔案由哪些進程開啟。在收集關於應用程式工作情況的資訊時,或在進行某些可能損壞資料的操作前確保檔案未被使用時,這一點特別重要lsof 更進階的用法可以協助您尋找刪除的檔案,並獲得關於網路連接的資訊。這是一個功能強大的工具,它幾乎可以用於任何地方。

 

原文連結:http://www.ibm.com/developerworks/cn/aix/library/au-lsof.html

linux/unix lsof用法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.