Inotify


使用inotifyAPI的幾個關鍵步驟:

1、使用inotify_init()創建一個inotify實例,返回一個文件描述符

2、使用inotify_add_watch()向inotify實例的監控列表添加條目。每個監控項都包含一個路徑名以及相關的位掩碼。位掩碼針對路徑名指明瞭所要監控的事件集合。函數返回一個監控描述符,用於指代該監控項

3、針對inotify文件描述符執行read()操作,每次對read()的成功調用,都會返回一個或多個inotify_event結構,其中各自記錄了處於inotify實例監控之下的某一路徑名所發生的事件。

4、關閉inotify文件描述符。這會自動清除與inotify實例相關的所有監控項



inotify機制可用於監控文件或目錄,當監控目錄時,與路徑自身及其所含文件相關的事件都會通知給應用程序。但inotify機制是非遞歸的,若需要監控整個目錄子樹,則需對該樹中中的每個目錄發起inotify_add_watch()調用。可使用select()、poll()、epoll()以及由信號驅動的I/O來監控inotify文件描述符。只要有事件可供讀取,上述API便會將inotify文件描述符標記爲可讀。

inotify機制屬於可選的Linux內核組件,通過CONFIG_INOTIFY和CONFIG_INOTIFY_USER選項配置。



Inotify API

#include <sys/inotify.h>

int inotify_init(void);


#include <sys/inotify.h>

int inotify_add_watch(int fd, const char *pathname, uint32_t mask);

可追加新的監控項,也可修改現有監控項

pathname標識欲創建或修改的監控項所對應的文件,調用程序必須對該文件具有讀權限(調用inotify_add_watch()時,會對文件權限做一次性檢查。只要監控項繼續存在,即便有人更改了文件權限,使調用程序不再對文件具有讀權限,調用程序依然會繼續收到文件的通知消息)。


#include <sys/inotify.h>

int inotify_rm_watch(int fd, uint32_t wd);

刪除監控項會爲該監控描述符生成IN_IGNORED事件。




Inotify事件

位值

In

Out

描述

IN_ACCESS

文件被訪問(read)

IN_ATTRIB

文件元數據改變

IN_CLOSE_WRITE

關閉爲了寫入而打開的文件

IN_CLOSE_NOWRITE

關閉以只讀方式打開的文件

IN_CREATE

在受監控的目錄內創建了文件/目錄

IN_DELETE

在受監控目錄內刪除文件/目錄

IN_DELETE_SELF

刪除受控目錄/文件本身

IN_MODIFY

文件被修改

IN_MOVE_SELF

移動受監控目錄/文件本身

IN_MOVED_FROM

文件移出到受控目錄之外

IN_MOVED_TO

將文件移入受控目錄

IN_OPEN

文件被打開

IN_ALL_EVENTS


以上所有輸出事件的統稱

IN_MOVE


IN_MOVED_ FROM|TO的統稱

IN_CLOSE


IN_CLOSE_ WRITE|NOWRITE的統稱

IN_DONT_FOLLOW


不對符號鏈接解引用

IN_MASK_ADD


將事件追加到pathname的當前監控掩碼

IN_ONESHOT


只監控pathname的一個事件

IN_ONLYDIR


pathname不是目錄會失敗

IN_IGNORED


監控項爲內核或應用程序所移除

IN_ISDIR


name中返回的所有文件名爲路徑

IN_Q_OVERFLOW


事件隊列溢出

IN_UNMOUNT


包含對象的文件系統遭卸載


細節:

當文件元數據(比如,權限、所有權、鏈接計數、擴展屬性、用戶ID、組ID等)改變時,會發生IN_ATTRIB事件。

IN_DONT_FOLLOW、IN_MASK_ADD、IN_ONESHOT和IN_ORLYDIR位並非對監控事件的定義,而是意在控制inotify_add_watch()系統調用的行爲。

IN_DONT_FOLLOW規定,若pathname爲符號鏈接,則不對其解引用,而是監控符號鏈接

若對已爲同一inotify描述符所監控的同一路徑名再次執行inotify_add_watch()調用,那麼默認情況下會用給定的mask掩碼來替換該監控項的當前掩碼。如果指定了IN_MASK_ADD,則會用mask與當前掩碼相或

IN_ONESHOT允許只監控pathname一個事件,事件發生後,監控項自動消失

只有pathname爲目錄時,IN_ONLYDIR才允許應用程序對其進行監控,否則報錯爲ENOTDIR。如要確保監控對象爲目錄,該標誌可以避免競爭條件的發生



讀取inotify事件

可用read()從inotify文件描述符中讀取事件,以判定發生了哪些事件。若時至讀取時尚未發生任何事件,read()會阻塞下去,直至有事件產生(除非對該文件描述符設置了O_NONBLOCK狀態標誌,這時若無任何事件可讀,read()將立即失敗,並報錯EAGAIN)。

事件發生後,每次調用read()會返回一個緩衝區,內含一個或多個如下類型的結構

struct inotify_event {

int wd; \\Watch descriptor on which event occurred

uint32_t mask; \\Bits descriping event that occurred

uint32_t cookie; \\Cookie for related events

uint32_t len; \\Size of 'name' field

char name[]; \\Optional null-terminated filename

};


mask字段返回該事件的位掩碼,注意下列更多的細節:

移出監控項時,會產生IN_IGNORED事件,起因可能由兩個:其一,應用程序使用了inotify_rm_watch()系統調用顯式移除監控項;其二,因受監控對象被刪除或其所駐留的文件系統遭卸載,致使內核隱式刪除監控項,以IN_ONESHOT而建立的監控項因事件觸發而遭自動移除時,不會產生IN_INGORED事件。

如果事件主體爲路徑,那麼除去其它位以外,在mask中還會設置IN_ISDIR位。

IN_UNMOUT事件會通知應用程序包含受監控對象的文件系統已遭卸載。該事件發生後還會產生包含IN_IGNORED置位的附加事件。

cookie字段可將相關事件聯繫在一起。目前,只有在對文件重命名時纔會用到該字段。這種情況下,系統會對重命名文件所在目錄產生IN_MOVED_FORM事件,然後,會針對重命名後文件的所在目錄產生IN_MOVED_TO事件。兩個事件cookie值相等


name,當受監控目錄中有文件發生事件時,name字段返回一個以空字符結尾的字符串,以標識該文件。若受監控對象自身有事件發生,則不使用name字段,將len字段置爲0。

len字段標識name的字節數,name的字符串結尾和下一個inotify_event結構的開始之間,可能會由額外的填充字節,單個inotify事件的長度是sizeof(struct inotify_event)+len



如果傳遞給read()緩衝區過小,將失敗並返回EINVAL,只要確保緩衝區足以容納下至少一個事件即可,傳給read()的緩衝區應至少爲sizeof(struct inotify_event)+NAME_MAX+1。對inotify描述符所執行的read(),將在已發生事件數量與緩衝區可容納事件數量間去最小值並返回之。

針對文件描述符fd調用ioctl(fd,FIONREAD,&namebytes),會返回其所指代的inotify實例中的當前可讀字節數。


從inotify文件描述符中讀取的事件形成了一個有序隊列,在事件隊列末尾追加一個新事件時,如果此新事件與隊列當前尾部事件有相同的wd,mask,cookie值,那麼內核會將兩者合併。




隊列限制和/proc文件

對inotify事件做排隊處理,需要消耗內核內存,所以內核會對inotify機制的操作施以各種限制。超級用戶可配置/proc/sys/fs/inotify路徑中的3個文件來調整這些限制:

max_queued_events 默認值16384

調用inotify_init()時,使用該值來爲新的inotify實例隊列中的事件數量設置上限,一旦超過這一上限,系統將生成IN_Q_OVERFLOW事件,並丟棄多餘事件,溢出事件的wd字段值爲-1。

max_user_instances 默認值128

對由每個真實用戶ID創建inotify實例數的限制值

max_user_watches 默認值8192

對由每個真實用戶ID創建的監控項數量的限制值


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章