本文主要向大家介紹了如何使用inotify控制Linux檔案系統中的事件。在具體的學習之前我們先來看看什麼是inotify以及他的曆史簡介。我們還會向大家介紹inotify的具體應用情況以及使中遇到問題的解決方案。
inotify 介紹
檔案系統事件監控對於從檔案管理工具到安全工具等多種程式來說都是必要的。自 2.6.13 版本核心開始,Linux 就提供 inotify 功能,這允許監控程式開啟一個獨立檔案描述符,並針對一系列特定的事件來監控一個或多個檔案或者目錄,例如開啟、關閉、移動/重新命名、 刪除、建立或者改變屬性。在以後的版本中還提供更多增強功能,因此在依賴這些特性之前請先檢查系統的核心版本。
在本文中,您將學會如何在簡單的監控程式當中使用 inotify 函數。下載範例代碼 並在系統當中進行編譯,來為後面的研究做準備。
曆史簡介
在 inotify 之前有 dnotify 。不幸的是,dnotify 有局限性,無法滿足使用者的需求, inotify 的優勢如下:
Inotify 採用簡單的檔案描述符,而 dnotify 需要為每個受監控的目錄開啟一個檔案描述符。 這使得同時監控多個目錄成本很高,而且還會遇到每進程檔案描述符限制問題。
inotify 所採用的檔案描述符通過系統調用獲得,並且沒有相關的裝置或檔案。對於 dnotify ,檔案描述符與目錄關係固定,避免了相關裝置未被載入的問題,這是抽取式媒體的典型問題。對於 inotify ,如果受監控檔案或目錄所在的檔案系統未被載入, 則會產生一個事件,然後該監控會被自動移除。
Inotify 能夠監控檔案或目錄。Dnotify 監控目錄, 因此程式員必須保持 stat 結構或者等效的資料結構,來反映目錄當中被監控的檔案, 然後在一個事件發生時,將其與目前狀態進行對比,來知曉目錄當中的條目發生了什麼情況。
如前面所述,inotify 採用檔案描述符,允許程式員採用標準 select 或者 poll 函數來對事件進行監控。 這允許高效的多重 I/O 或者與 Glib 的 mainloop 整合。相比之下,dnotify 採用訊號, 這使得程式員感到難度更大或者不夠流暢。 在 2.6.25 版本核心中,inotify 也增加了 Signal-drive I.O 通告功能。
用於 inotify 的 API
Inotify 提供簡單的 API ,採用最小的檔案描述符並允許細粒度監控。與 inotify 的通訊通過系統調用實現。
inotify_init
是用於建立 inotify 執行個體的系統調用,並返回一個指向該執行個體的檔案描述符。
inotify_init1
與 inotify_init 相似,並帶有附加標誌。如果這些標誌沒有指定,將採用與 inotify_init 相同的值。
inotify_add_watch
增加對檔案或目錄的監控並指定需要監控哪些事件。 標誌用於控制是否將事件加入到已有的監控當中,是否只有路徑代表一個目錄才進行監控, 是否需要追蹤符號連結,是否進行一次性監控,當首次出現事件後就停止監控。
inotify_rm_watch
從監控列表中移除監控項目。
read
讀取包含一個或多個事件資訊的緩衝。
close
關閉檔案描述符,並移除所有在該描述符上的監控。 當關於某一執行個體的檔案描述符都關閉以後, 資源和下層的對象都將釋放,來供核心再次使用。
因此,典型的監控程式要進行如下操作:
利用 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 標誌。