如何監控Linux文件系統事件:inotify使用指南
§·inotify初識
Inotify 是一個 Linux特性,它監控文件系統操作,比如讀取、寫入和創建。Inotify 反應靈敏,用法非常簡單,并且比 cron 任務的繁忙輪詢高效得多。學習如何將 inotify 集成到您的應用程序中,并發現一組可用來進一步自動化系統治理的命令行工具。
§·inotify產生背景
系統治理就像日常生活一樣。就像刷牙和吃蔬菜一樣,日常的維護能保持機器的良好狀態。您必須定期清空廢物,比如臨時文件或無用的日志文件,以及花時間填寫表單、回復電話、更新和監控進程等。幸好自動化 shell 腳本、使用 Nagios 等工具進行監控、通過常見的 cron 進行任務調度可以減輕這個負擔。
但稀奇的是,這些工具沒有一個具有響應性。當然,您可以安排一個頻繁運行的 cron 任務來監控條件,但這樣繁忙的輪詢 — 消耗大量資源并且具有不確定性 — 并不是很理想。
例如,假如您必須監控輸入數據的幾個 Transfer Protocol(FTP)收存箱,您可能要通過 find 命令掃描每個目標目錄,列舉新的內容。然而,盡管這個操作看起來并沒有什么害處,但每個調用都產生一個新的 shell 和 find 命令,這需要許多系統調用來打開目錄,然后掃描目錄,等等。這會造成過于頻繁的或大量的輪詢任務(更糟糕的是,繁忙的輪詢并不總是很好。想象一下一個文件系統瀏覽器,比如 Mac OS X 的 Finder,輪詢更新時需要的大量資源及其復雜性)。那么,管理員應該怎么辦呢?令人興奮的是,您可以再次求助于可以信賴的計算機。
§·inotify詳細介紹
Inotify 是一個 Linux 內核特性,它監控文件系統,并且及時向專門的應用程序發出相關的事件警告,比如刪除、讀、寫和卸載操作等。您還可以跟蹤活動的源頭和目標等細節。
使用 inotify 很簡單:創建一個文件描述符,附加一個或多個監視器(一個監視器 是一個路徑和一組事件),然后使用 read 方法從描述符獲取事件。read 并不會用光整個周期,它在事件發生之前是被阻塞的。
更好的是,因為 inotify 通過傳統的文件描述符工作,您可以利用傳統的 select 系統調用來被動地監控監視器和許多其他輸入源。
兩種方法 — 阻塞文件描述符和使用 select— 都避免了繁忙輪詢?,F在,深入了解 inotify,寫一些 C 代碼,然后看看一組命令行工具,可以構建并使用它們將命令和腳本附加到文件系統事件。Inotify 不會在中途失去控制,但它可以運行 cat 和 wget,并且在必要時嚴格執行。
要使用 inotify,必須具備一臺帶有 2.6.13 或更新內核的 Linux 機器(以前的 Linux 內核版本使用更低級的文件監控器 dnotify)。如果不知道內核的版本,請轉到 shell,輸入 uname -a:
% uname -a
Linux ubuntu-desktop 2.6.24-19-generic #1 SMP … i686 GNU/Linux
如果列出的內核版本不低于 2.6.13,系統就支持 inotify。還可以檢查機器的 /usr/include/sys/inotify.h 文件。
如果它存在,表明內核支持 inotify。
注意:FreeBSD 和 Mac OS X 提供一個類似于 inotify 的 kqueue。在 FreeBSD 機器上輸入 man 2 kqueue 獲取更多信息。
本文基于 Ubuntu Desktop version 8.04.1(即 Hardy),它運行在 Mac OS X version 10.5 Leopard 的 Parallels Desktop version 3.0。
§·inotify其它介紹
當需要對Linux文件系統進行高效率、細粒度、異步地監控時,可以采用 inotify。
可利用它對用戶空間進行安全、性能、以及其他方面的監控。
inotify允許監控程序打開一個獨立文件描述符,并針對事件集監控一個或者多個文件,例如打開、關閉、移動/重命名、刪除、創建或者改變屬性。
從文件管理器到安全工具,文件系統監控對于的許多程序來說都是必不可少的。從 Linux 2.6.13 內核開始,Linux 就推出了 inotify,允許監控程序打開一個獨立文件描述符,并針對事件集監控一個或者多個文件,例如打開、關閉、移動/重命名、刪除、創建或者改變屬性。在后期的內核中有了很多增強,因此在依賴這些特性之前,請先檢查您的內核版本。
§·inotify功能簡單介紹
在本文中,您將會學習如何在簡單的監控應用程序中使用 inotify 功能。下載樣例代碼,在您的系統上編譯,進一步探索。
※·dnotify 與 inotify 對比
在 inotify 之前有 dnotify。不幸的是,dnotify 有局限性,用戶需要更好的產品。和 dnotify 相比 inotify 的優勢如下:
1 . Inotify 使用一個獨立的文件描述符,而 dnotify 需要為每個受監控的目錄打開一個文件描述符。當您同時監控多個目錄時成本會非常高,而且還會遇到每進程文件描述符限制。
2 . Inotify 所使用的文件描述符可以通過系統調用獲得,并且沒有相關設備或者文件。而使用 dnotify,文件描述符就固定了目錄,妨礙備用設備卸載,這是可移動媒體的一個典型問題。對于 inotify,卸載的文件系統上的監視文件或目錄會產生一個事件,而且監視也會自動移除。
3 . Inotify 能夠監視文件或者目錄。Dnotify 則只監視目錄,因此程序員還必須保持 stat 結構或者一個等效的數據結構,來反映該被監視目錄中的文件,然后在一個事件發生時,將其與當前狀態進行對比,以此了解當前目錄中的條目發生了什么情況。
小結:如上所述,inotify 使用文件描述符,允許程序員使用標準 select 或者 poll 函數來監視事件。這允許高效的多路復用 I/O 或者與 Glib 的 mainloop 的集成。相比之下,dnotify 使用信號,這使得程序員覺得比較困難或者不夠流暢。在 2.6.25 內核中 inotify 還添加了 Signal-drive I.O 通知功能。
※·用于 inotify 的 API
Inotify 提供一個簡單的 API,使用最小的文件描述符,并且允許細粒度監控。與 inotify 的通信是通過系統調用實現??捎玫暮瘮等缦滤荆?/span>
◎·inotify_init
是用于創建一個 inotify 實例的系統調用,并返回一個指向該實例的文件描述符。
◎·inotify_init1
與 inotify_init 相似,并帶有附加標志。如果這些附加標志沒有指定,將采用與 inotify_init 相同的值。
◎·inotify_add_watch
增加對文件或者目錄的監控,并指定需要監控哪些事件。標志用于控制是否將事件添加到已有的監控中,是否只有路徑代表一個目錄才進行監控,是否要追蹤符號鏈接,是否進行一次性監控,當首次事件出現后就停止監控。
◎·inotify_rm_watch
從監控列表中移出監控項目。
◎·read
讀取包含一個或者多個事件信息的緩存。
◎·close
關閉文件描述符,并且移除所有在該描述符上的所有監控。當關于某實例的所有文件描述符都關閉時,資源和下層對象都將釋放,以供內核再次使用。
※·用于 inotify 監控程序
因此,典型的監控程序需要進行如下操作:
使用 inotify_init 打開一個文件描述符
添加一個或者多個監控
等待事件
處理事件,然后返回并等待更多事件
當監控不再活動時,或者接到某個信號之后,關閉文件描述符,清空,然后退出。
在下一部分中,您將看到可以監控的事件,它們如何在簡單的程序中運行。最后,您將看到事件監控如何進行。
◎·通告
當您的應用程序讀取到一個通告時,事件的順序也被讀取到您提供的緩存中。事件在一個變長結構中被返回,如清單 1 所示。如果數據占滿了您的緩存,您可能需要對最后一個條目進行局部事件信息或者局部名處理。
清單 1. 用于 inotify 的事件結構體
struct inotify_event
{
int wd; /* Watch descriptor. */
uint32_t mask; /* Watch mask. */
uint32_t cookie; /* Cookie to synchronize two events. */
uint32_t len; /* Length (including NULs) of name. */
char name __flexarr; /* Name. */
};
請注意,只有當監控對象是一個目錄并且事件與目錄內部相關項目有關,而與目錄本身無關時,才提供 name 字段。如果 IN_MOVED_FROM 事件與相應的 IN_MOVED_TO 事件都與被監控的項目有關,cookie 就可用于將兩者關聯起來。事件類型在掩碼字段中返回,并伴隨著能夠被內核設置的標志。例如,如果事件與目錄有關,則標志 IN_ISDIR 將由內核設置。
◎·可監控的事件
有幾種事件能夠被監控。一些事件,比如 IN_DELETE_SELF 只適用于正在被監控的項目,而另一些,比如 IN_ATTRIB 或者 IN_OPEN 則只適用于監控過的項目,或者如果該項目是目錄,則可以應用到其所包含的目錄或文件。
IN_ACCESS
被監控項目或者被監控目錄中的條目被訪問過。例如,一個打開的文件被讀取。
IN_MODIFY
被監控項目或者被監控目錄中的條目被修改過。例如,一個打開的文件被修改。
IN_ATTRIB
被監控項目或者被監控目錄中條目的元數據被修改過。例如,時間戳或者許可被修改。
IN_CLOSE_WRITE
一個打開的,等待寫入的文件或目錄被關閉。
IN_CLOSE_NOWRITE
一個以只讀方式打開的文件或目錄被關閉。
IN_CLOSE
一個掩碼,可以很便捷地對前面提到的兩個關閉事件(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)進行邏輯操作。
IN_OPEN
文件或目錄被打開。
IN_MOVED_FROM
被監控項目或者被監控目錄中的條目被移出監控區域。該事件還包含一個 cookie 來實現 IN_MOVED_FROM 與 IN_MOVED_TO 的關聯。
IN_MOVED_TO
文件或目錄被移入監控區域。該事件包含一個針對 IN_MOVED_FROM 的 cookie。如果文件或目錄只是被重命名,將能看到這兩個事件,如果它只是被移入或移出非監控區域,將只能看到一個事件。如果移動或重命名一個被監控項目,監控將繼續進行。參見下面的 IN_MOVE-SELF。
IN_MOVE
可以很便捷地對前面提到的兩個移動事件(IN_MOVED_FROM | IN_MOVED_TO)進行邏輯操作的掩碼。
IN_CREATE
在被監控目錄中創建了子目錄或文件。
IN_DELETE
被監控目錄中有子目錄或文件被刪除。
IN_DELETE_SELF
被監控項目本身被刪除。監控終止,并且將收到一個 IN_IGNORED 事件。
IN_MOVE_SELF
監控項目本身被移動。
除了事件標志以外,還可以在 inotify 頭文件(/usr/include/sys/inotify.h)中找到其他幾個標志。例如,如果只想監控第一個事件,可以在增加監控時設置 IN_ONESHOT 標志。
inotify 的可能使用
您可以將 inotify 用于多種目標。下面列舉一些可能的情況:
◎·性能監控
您可能想確定應用程序打開最頻繁的文件是哪個。如果發現一個小文件被頻繁打開與關閉,您可能會考慮采用內存版,或者改變應用程序來采取其他方式共享該數據。
元信息
您可能想記錄文件的附加信息,例如起始創建時間或者最后改變該文件的用戶 id。
安全
您可能會因為安全原因,需要對特定文件或目錄的所有訪問進行監控。
我們的示例代碼監控所有事件并進行報告。實際上,您可能想依據您的需要,來查看這些事件的特定子集。您可能想監控不同被監控項目的不同事件。例如,您可能想監控文件的打開與關閉事件,但對于目錄只想監控創建與刪除事件。在任何可能的時候,您可以監控您所感興趣的最小事件集。
結束語
應用到性能監控、程序調試、以及自動化等領域時,inotify 是監控 Linux 文件系統的功能強大的、高粒度的機制。利用本文提供的樣例代碼,您可以開始編寫用來實時記錄文件系統事件并最小化性能開銷的應用程序。
原創文章,作者:linux_root,如若轉載,請注明出處:http://www.www58058.com/56011