inotify

1、簡介shell

Inotify 是一個 Linux 內核特性,它監控文件系統,而且及時向專門的應用程序發出相關的事件警告,好比刪除、讀、寫和卸載操做等。您還能夠跟蹤活動的源頭和目標等細節。在實際項目中,若是項目帶有配置文件,那麼怎麼讓配置文件的改變和項目程序同步而不須要重啓程序呢?一個明顯的應用是:在一個程序中,使用Inotify監視它的配置文件,若是該配置文件發生了更改(更新,修改)時,Inotify會產生修改的事件給程序,應用程序就能夠實現從新加載配置文件,檢測哪些參數發生了變化,並在應用程序內存的一些變量作相應的修改。固然另外一種方法能夠是經過cgi註冊命令,並經過命令更新內存數據及更新配置文件
cookie

Inotify 能夠監視的文件系統事件包括:
IN_ACCESS,即文件被訪問
IN_MODIFY,文件被 write
IN_ATTRIB,文件屬性被修改,如 chmod、chown、touch 等
IN_CLOSE_WRITE,可寫文件被 close
IN_CLOSE_NOWRITE,不可寫文件被 close
IN_OPEN,文件被 open
IN_MOVED_FROM,文件被移走,如 mv
IN_MOVED_TO,文件被移來,如 mv、cp
IN_CREATE,建立新文件
IN_DELETE,文件被刪除,如 rm
IN_DELETE_SELF,自刪除,即一個可執行文件在執行時刪除本身
IN_MOVE_SELF,自移動,即一個可執行文件在執行時移動本身
IN_UNMOUNT,宿主文件系統被 umount
IN_CLOSE,文件被關閉,等同於(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
IN_MOVE,文件被移動,等同於(IN_MOVED_FROM | IN_MOVED_TO)
注:上面所說的文件也包括目錄。
測試


2、使用Inofityflex

要使用 inotify,您必須具有一臺帶有 2.6.13 或更新內核的 Linux 機器(之前的 Linux 內核版本使用更低級的文件監控器dnotify)。若是您不知道內核的版本,請轉到 shell,輸入 uname -aui


 

您還能夠檢查機器的 /usr/include/sys/inotify.h 文件。若是它存在,代表您的內核支持 inotify。spa

使用 inotify 很簡單:建立一個文件描述符,附加一個或多個監視器(一個監視器 是一個路徑和一組事件),而後使用 read()方法從描述符獲取事件信息。read() 並不會用光整個週期,它在事件發生以前是被阻塞的。.net

更好的是,由於 inotify 經過傳統的文件描述符工做,您能夠利用傳統的 select() 系統調用來被動地監控監視器和許多其餘輸入源。兩種方法 — 阻塞文件描述符和使用 select()— 都避免了繁忙輪詢。code

 

Inotify 提供 3 個系統調用,它們能夠構建各類各樣的文件系統監控器:blog

  • int fd = inotify_init() 在內核中建立 inotify 子系統的一個實例,成功的話將返回一個文件描述符,失敗則返回 -1。就像其餘系統調用同樣,若是 inotify_init() 失敗,請檢查 errno 以得到診斷信息。
  • 顧名思義, int wd = inotify_add_watch(fd,path,mask) 用於添加監視器。每一個監視器必須提供一個路徑名和相關事件的列表(每一個事件由一個常量指定,好比 IN_MODIFY)。要監控多個事件,只需在事件之間使用邏輯操做符或 — C 語言中的管道線(|)操做符。若是 inotify_add_watch() 成功,該調用會爲已註冊的監視器返回一個唯一的標識符;不然,返回 -1。使用這個標識符更改或刪除相關的監視器。
  • int ret = inotify_rm_watch(fd, wd) 刪除一個監視器。

此外,還須要 read() 和 close() 系統調用。若是描述符由 inotify_init() 生成,則調用 read() 等待警告。假設有一個典型的文件描述符,應用程序將阻塞對事件的接收,這些事件在流中表現爲數據。文件描述符上的由 inotify_init() 生成的通用close() 刪除全部活動監視器,並釋放與 inotify 實例相關聯的全部內存(這裏也用到典型的引用計數警告。與實例相關聯的全部文件描述符必須在監視器和 inotify 消耗的內存被釋放以前關閉)。事件

3、測試Inotify

在文件 /usr/include/sys/inotify.h. 中,您能夠找到事件結構的定義,它是一種 C 結構,以下所示:

 

  1. struct inotify_event   
  2. {  
  3.   int wd;       /* The watch descriptor */  
  4.   uint32_t mask;    /* Watch mask */  
  5.   uint32_t cookie;  /* A cookie to tie two events together */  
  6.   uint32_t len;     /* The length of the filename found in the name field */  
  7.   char name __flexarr;  /* The name of the file, padding to the end with NULs */      
  8. }  

結構中的char name是不佔空間的,至關於char name[0],因此sizeof(struct inotify_event)長度是16,實際上該結構數據的總長度應該是16+len,數據是緊跟在uinit32_t len後面的數據。

測試代碼以下:

 

  1. #include <stdio.h>//printf  
  2. #include <string.h> //strcmp  
  3. #include <sys/inotify.h>//inotify_init inotify_add_watch....  
  4. #include <sys/select.h>//select timeval  
  5. #include <unistd.h>//close  
  6.   
  7. #define EVENT_SIZE  ( sizeof (struct inotify_event) )  
  8. #define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )  
  9. #define ERR_EXIT(msg,flag)  {perror(msg);goto flag;}  
  10.   
  11. int main( int argc, char **argv )   
  12. {  
  13.     int length, i = 0;  
  14.     int fd;  
  15.     int wd;  
  16.     char buffer[BUF_LEN];  
  17.   
  18.     if((fd = inotify_init()) < 0)  
  19.         ERR_EXIT("inotify_init",inotify_init_err);  
  20.   
  21.     if( (wd = inotify_add_watch( fd, "/tmp",    IN_MODIFY | IN_CREATE | IN_DELETE ) ) < 0)  
  22.         ERR_EXIT("inofity_add_watch", inotify_add_watch_err);  
  23.       
  24.     fd_set rfd;  
  25.     struct timeval tv;  
  26.     tv.tv_sec = 0;  
  27.     tv.tv_usec = 10000;//10millsecond  
  28.     while(true)  
  29.     {  
  30.         int retval;  
  31.         FD_ZERO(&rfd);  
  32.         FD_SET(fd, &rfd);  
  33.         retval = select(fd + 1, &rfd, NULL, NULL, &tv);  
  34.         if(retval == 0) continue;  
  35.         else if(retval == -1)  
  36.             ERR_EXIT("select",select_err);  
  37.   
  38.         // retval > 0  
  39.         length = read( fd, buffer, BUF_LEN );    
  40.         if(length < 0)  
  41.             ERR_EXIT("read",read_err);  
  42.   
  43.         //length >= 0  
  44.         int i = 0;  
  45.         while ( i < length )   
  46.         {  
  47.             struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];  
  48.             if ( event->len )   
  49.             {  
  50.                 if ( event->mask & IN_CREATE )   
  51.                 {  
  52.                     if ( event->mask & IN_ISDIR )   
  53.                         printf( "The directory %s was created.\n", event->name );         
  54.                     else  
  55.                         printf( "The file %s was created.\n", event->name );  
  56.                     if(strcmp(event->name,"kill") == 0)  
  57.                         ERR_EXIT("success exit",success_exit);  
  58.   
  59.                 }  
  60.                 else if ( event->mask & IN_DELETE )   
  61.                 {  
  62.                     if ( event->mask & IN_ISDIR )   
  63.                         printf( "The directory %s was deleted.\n", event->name );         
  64.                     else  
  65.                         printf( "The file %s was deleted.\n", event->name );  
  66.                 }  
  67.                 else if ( event->mask & IN_MODIFY )   
  68.                 {  
  69.                     if ( event->mask & IN_ISDIR )  
  70.                         printf( "The directory %s was modified.\n", event->name );  
  71.                     else  
  72.                         printf( "The file %s was modified.\n", event->name );  
  73.                 }  
  74.             }else  
  75.             {  
  76.                 //TODO  
  77.                 //when only a file(not directory) is specified by add watch function, event->len's value may be zero, we can handle it here  
  78.             }  
  79.             i += EVENT_SIZE + event->len;  
  80.         }  
  81.     }  
  82. success_exit:  
  83.     ( void ) inotify_rm_watch( fd, wd );  
  84.     ( void ) close( fd );  
  85.     return 0;  
  86.   
  87. read_err:  
  88. select_err:  
  89. inotify_add_watch_err:  
  90.     ( void ) inotify_rm_watch( fd, wd );  
  91. inotify_init_err:  
  92.     ( void ) close( fd );  
  93.   
  94.     return -1;  
  95. }  

以上代碼須要注意的地方:

 1.若是在/tmp目錄下touch kill文件,程序則會退出

2.若是隻有一個add watch 一個file,那麼這個file的更改產生的event事件中event->len是爲0,須要額外的處理,此代碼省略了具體的處理過程,以註釋代替

3.若是監測的是文件或目錄的更改,使用 echo "xxx" >> file,會產生一個event事件,而使用echo "xxx" > file 會產生兩個event事件,查了相關的資料,多是由於後者須要先清空file文件內容,形成第一次event事件,再將xxx寫入file保存,形成了第二次的event事件。

相關文章
相關標籤/搜索