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 <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 }
总的来说,虽然这只是一个很简单的功能,但还是为自己的一小步提升而高兴,在此分享给各位一起进步。
单单代码逻辑可修改的地方就有很多,还望大家见谅。