Inotify机制的简单应用


编程之路刚刚开始,错误难免,希望大家能够指出。

一、Inotify机制

1.简单介绍inotify:Inotify可用于检测单个文件,也可以检测整个目录。当检测的对象是一个目录的时候,目录本身和目录里的内容都会成为检测的对象。

此种机制的出现的目的是当内核空间发生某种事件之后,可以立即通知到用户空间。方便用户做出具体的操作。

2.inotify的三个API:

  inotify_init(void)                        

  用于创建一个inotify的实例,然后返回inotify事件队列的文件描述符。

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

  该函数用于添加“watch list”,也就是检测列表。 可以是一个新的watch,也可以是一个已经存在的watch。其中fd就是inotify_init的返回值,pathname是要检测目录或者文件的路径,mask就是要检测的事件类型。该函数成功返回的是一个unique的watch描述符。

  inotify_rm_watch(int fd, int wd)                    

  用于从watch list种移除检测的对象。

3.读取事件:

  使用read系统调用可以获取至少一个(必定为整数个,当剩余空间不足容纳下一个结构体时,该结构体只能下次read获取)的inotify_event结构体。

1 struct inotify_event {  
2     int      wd;           /*watch描述符 */  
3     uint32_t mask;     /*  事件掩码 */  
4     uint32_t cookie;   
5     uint32_t len;      /* name的长度 */  
6     char     name[];   /* 文件或目录名 */  
7 };  

  切记如果read()的读取缓冲区如果小于一个inotify_event的长度,read会返回错误,所以建议缓冲区为每个inotify_event的长度假定为“sizeof(struct inotify_event) + NAME_MAX +1”,“NAME_MAX”是系统文件名最大长度的宏定义。

二、sigaction 函数

1.int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)      这个系统调用的作用是改变进程接收到的指定信号的行动。

  signum : 说明具体信号,它可以是除了SIGKILL和SIGSTOP之外的任何有效信号值。

  act : 将要安装的signum定义信号的新行动。

  oldact: 用来保存signum定义信号的过去的行动。

2.目前个人所了解的sigaction和signal的区别:

  1.signal只能对信号进行一次自定义处理,之后恢复默认操作,sigaction可以进行反复调用;

  2.signal处理过程中无法阻塞某些信号,而sigaction可以阻塞它自身和其他信号;

3.sigaction 结构体定义如下:

 1 struct sigaction {
 2 
 3     void (*sa_handler)(int);    设置为SIG_DFL表示默认行动,设置为SIG_IGN表示忽略这个信号,或者设置为处理函数的指针。
 4 
 5     void (*sa_sigaction)(int,  siginfo_t* , vid*);
 6 
 7     sigset_t sa_mask;    这个参数指明了在信号处理函数执行过程中应该被阻止的信号的mask值(包括它自己)。
 8 
 9     int sa_flags;   改变信号的行为;
10 
11     void (*sa_restorer)(void);
12 
13 };

简单说明一下思路:
  1.将argv[1]指定的目录及其子目录都设置为受监控目录;

  2.不断去read事件,并将事件指定记录在某个文件内,并存有时间发生的大概时间;

  3.进程需要通过发送“SIGINT”信号来进行停止。

  1 #define _XOPEN_SOURCE 500
  2 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include 
  9 #include <string.h>
 10 #include 
 11 #include 
 12 #include 
 13 #include 
 14 #include 
 15 #include 
 16 
 17 #define BUF_SIZE (10 *(sizeof(struct inotify_event) + NAME_MAX +1))
 18 #define INOTIFT_EVENT (IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO)
 19 
 20 struct pathInfo
 21 {
 22     int wd;
 23     char czPath[256];
 24     struct pathInfo *pNext;
 25 };
 26 
 27 struct eventInfo
 28 {
 29     int event;
 30     char explain[30];
 31 };
 32 
 33 static struct eventInfo g_stEventInfo[] =
 34 {
 35     {IN_CREATE,"create file"},
 36     {IN_DELETE,"delete file"},
 37     {IN_DELETE_SELF,"delete file"},
 38     {IN_MODIFY,"alter file"},
 39     {IN_MOVED_FROM,"lose file"},
 40     {IN_MOVED_TO,"append file"},
 41 };
 42 
 43 int g_inotifyFd;
 44 FILE *g_fp;
 45 struct pathInfo *g_list;
 46 
 47 /*
 48 IN_CREATE               在受监控目录下创建了文件或目录
 49 IN_DELETE               在受监控目录内删除了文件或目录
 50 IN_DELETE_SELF          删除了受监控目录/文件本身
 51 IN_MODIFY               文件被修改
 52 IN_MOVED_FROM           文件移除受监控目录
 53 IN_MOVED_TO             将文件移到受监控目录
 54 */
 55 
 56 int myNfwt(const char *fpath,const struct stat *sb,int flag,struct FTW *ftwbuf)
 57 {
 58     if(flag != FTW_DP)
 59     {
 60         return 0;
 61     }
 62     int wd = inotify_add_watch(g_inotifyFd,fpath,INOTIFT_EVENT);
 63     if(wd == -1)
 64     {
 65         perror("inotify_add_watch");
 66         return -1;
 67     }
 68 
 69     struct pathInfo *pTemp = (struct pathInfo *)malloc(sizeof(struct pathInfo));
 70     memset(pTemp->czPath,0,sizeof(pTemp->czPath));
 71     pTemp->wd = wd;
 72     pTemp->pNext = NULL;
 73     if(strcpy(pTemp->czPath,fpath) == NULL)
 74     {
 75         perror("strcpy");
 76         return -2;
 77     }
 78 
 79     if(g_list == NULL)
 80     {
 81         g_list = pTemp;
 82         return 0;
 83     }
 84     else
 85     {
 86         if(g_list->pNext == NULL)
 87         {
 88             g_list->pNext = pTemp;
 89             return 0;
 90         }
 91         struct pathInfo *p = g_list->pNext;
 92         while(1)
 93         {
 94             if(p->pNext == NULL)
 95             {
 96                 p->pNext = pTemp;
 97                 return 0;
 98             }
 99             p = p->pNext;
100         }
101     }
102 }
103 
104 int watch_object(char *fileName)
105 {
106     int flags = FTW_PHYS | FTW_DEPTH;
107     int ret = nftw(fileName,myNfwt,896,flags);
108     if(ret == -1)
109     {
110         perror("nftw");
111         return -1;
112     }
113 
114     return 0;
115 }
116 
117 char *GetPath(int wd)
118 {
119     if(g_list == NULL)
120     {
121         return NULL;
122     }
123     if(g_list->wd == wd)
124     {
125         return g_list->czPath;
126     }
127     struct pathInfo *pTemp = g_list->pNext;
128 
129     while(1)
130     {
131         if(pTemp == NULL)
132         {
133             break;
134         }
135         if(pTemp->wd == wd)
136         {
137             return pTemp->czPath;
138         }
139         pTemp = pTemp->pNext;
140     }
141     return NULL;
142 }
143 
144 int recordEvent()
145 {
146     int iReadNum;
147     char czBuf[BUF_SIZE+1] = {0};
148     struct inotify_event *pEvent;
149     time_t now;
150     struct tm*tm_now;
151 
152     iReadNum = read(g_inotifyFd,czBuf,BUF_SIZE);
153     if(iReadNum == -1)
154     {
155         printf("read failed\n");
156         return -4;
157     }
158     else if(iReadNum == 0)
159     {
160         return 0;
161     }
162     time(&now);
163     tm_now = localtime(&now);
164     char *p = czBuf;
165     while(1)
166     {
167         if(p >= czBuf+iReadNum)
168         {
169             break;
170         }
171         pEvent = (struct inotify_event *)p;
172         char *pPath = GetPath(pEvent->wd);
173         if(pPath == NULL)
174         {
175             return -5;
176         }
177         for(int index = 0;index < sizeof(g_stEventInfo)/sizeof(struct eventInfo);index++)
178         {
179             if(pEvent->mask & (g_stEventInfo[index].event))
180             {
181                 fprintf(g_fp,"path : %-30s\t   event : %-30s\t   file name : %-30s\t   time : %s",pPath,g_stEventInfo[index].explain,pEvent->name,asctime(tm_now));
182                 break;
183             }
184         }
185         fflush(g_fp);
186         p += (sizeof(struct inotify_event) + pEvent->len);
187     }
188 
189     return 0;
190 }
191 
192 int GetFileLine()
193 {
194     char *p;
195     char czBuf[200] = {0};
196     int line = 0;
197     while(1)
198     {
199         p = fgets(czBuf,200,g_fp);
200         if(p == NULL)
201         {
202             return line;
203         }
204         line++;
205     }
206     return -1;
207 }
208 
209 int freeSpace(struct pathInfo **pInfo)
210 {
211     if(*pInfo == NULL)
212     {
213         return 0;
214     }
215     else
216     {
217         if((*pInfo)->pNext == NULL)
218         {
219             if(inotify_rm_watch(g_inotifyFd,(*pInfo)->wd) == -1)
220             {
221                 printf("notify_rm_watch error\n");
222             }
223             free((*pInfo));
224             *pInfo = NULL;
225             return 0;
226         }
227         else
228         {
229             freeSpace(&((*pInfo)->pNext));
230             if(inotify_rm_watch(g_inotifyFd,(*pInfo)->wd) == -1)
231             {
232                 printf("notify_rm_watch error\n");
233             }
234             free(*pInfo);
235             *pInfo = NULL;
236             return 0;
237         }
238     }
239     return -1;
240 }
241 
242 
243 void catch_signal(int sig)
244 {
245     if(sig == SIGINT)
246     {
247         int ret = freeSpace(&g_list);
248         if(ret < 0)
249         {
250             printf("free space failed\n");
251         }
252         close(g_inotifyFd);
253         fclose(g_fp);
254     }
255 }
256 
257 int main(int argc,char *argv[])
258 {
259     if(argc < 2)
260     {
261         printf("please input file/dir name:./a.ot File.txt\n");
262         return -1;
263     }
264 
265     g_inotifyFd = inotify_init();
266     if(g_inotifyFd == -1)
267     {
268         perror("inotify_init");
269         return -2;
270     }
271     int ret = watch_object(argv[1]);
272     if(ret != 0)
273     {
274         return -3;
275     }
276 
277     g_fp = fopen("/home/gc/Record_Jyb","a+");
278     if(g_fp == NULL)
279     {
280         perror("fopen");
281         return -4;
282     }
283 
284     struct sigaction stSign;
285     stSign.sa_handler = catch_signal;
286     sigemptyset(&stSign.sa_mask);
287     stSign.sa_flags = SA_RESETHAND;
288     sigaction(SIGINT,&stSign,0);
289 
290     while(1)
291     {
292         if(GetFileLine() >= 1000)
293         {
294             fclose(g_fp);
295             g_fp = fopen("/home/gc/Record_Jyb","w");
296             if(g_fp == NULL)
297             {
298                 perror("fopen");
299                 return -5;
300             }
301             fclose(g_fp);
302             g_fp = fopen("/home/gc/Record_Jyb","a+");
303             if(g_fp == NULL)
304             {
305                 perror("fopen");
306                 return -6;
307             }
308         }
309         ret = recordEvent();
310         if(ret < 0)
311         {
312             return -5;
313         }
314         sleep(10);
315     }
316 }

总的来说,虽然这只是一个很简单的功能,但还是为自己的一小步提升而高兴,在此分享给各位一起进步。

单单代码逻辑可修改的地方就有很多,还望大家见谅。

相关