编程之路刚刚开始,错误难免,希望大家能够指出。
一、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 <stdio.h>
4 #include <assert.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <sys/inotify.h>
12 #include <limits.h>
13 #include <fcntl.h>
14 #include <ftw.h>
15 #include <time.h>
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 }
总的来说,虽然这只是一个很简单的功能,但还是为自己的一小步提升而高兴,在此分享给各位一起进步。
单单代码逻辑可修改的地方就有很多,还望大家见谅。