在工作中对应需要将产生的日志文件进行显示,用到监控文件系统事件的一些函数,整理下笔记。
1、监控函数
inotify - monitoring file system events struct inotify_event { int wd; /* Watch descriptor */ uint32_t mask; /* Mask of events */ uint32_t cookie; /* Unique cookie associating related events (for rename(2)) */ uint32_t len; /* Size of name field */ char name[]; /* Optional null-terminated name */ }; int inotify_init(void); /* 初始化inotify实例,分配一个inotify事件队列,返回对应事件队列的文件描述符 */ int inotify_add_watch(int fd, const char *pathname, uint32_t mask); /* 监控 pathname目录,事件为mask,fd是inotify_init返回的事件队列描述符 常用mask:可以通过man inotify查看 IN_ACCESS 文件被使用 IN_CLOSE_WRITE 文件操作完成close,touch一个文件同时产生这个事件和IN_CREATE IN_CREATE 创建文件 IN_DELETE 删除文件 IN_MODIFY 文件被修改 IN_OPEN 文件被打开 */
2、怎么监控
1)通过inotify_init函数生成事件队列对应的文件描述符
2)通过inotify_add_watch函数添加监控目录和对应的事件
3)使用select函数监控事件队列描述符,有事件发生则读事件队列文件描述符
3、完整代码如下:
#include#include #include #include #include #include #include #include #include #include #include static int fd; static void die(int signo) { printf("sigon: %d\n",signo); close(fd); exit(-1); } static int watch_file(char *dir) { int ret = 0; int fd = 0; int fw = 0; struct stat statbuf; char buf[(sizeof(struct inotify_event) + 128 + 1) * 1024] = {0}; fd = inotify_init(); if (fd == -1) { return NULL; } fw = inotify_add_watch(fd, dir, IN_CREATE|IN_CLOSE_WRITE|IN_MOVED_FROM); if (fw == -1) { return NULL; } fd_set rfds; while(1) { FD_ZERO(&rfds); FD_SET(fd, &rfds); struct inotify_event *event = NULL; ret = select(fd + 1, &rfds, NULL, NULL, NULL); if (ret > 0 && FD_ISSET(fd, &rfds)) { ret = read(fd, buf, sizeof(buf) - 1); if (ret < 0) { continue; } int i = 0; while( i < ret) { char log_buf[256] = {0}; event = (struct inotify_event *)&buf[i]; if (event->len && (event->mask & IN_CREATE ) && event->name[0] != '.') { snprintf(log_buf, sizeof(log_buf) - 1, "%s/%s\n", "IN_CREATE file name:", event->name); printf("%s",log_buf); } else if (event->len && (event->mask & IN_CLOSE_WRITE) && event->name[0] != '.') { snprintf(log_buf, sizeof(log_buf) - 1, "%s/%s\n", "IN_CLOSE_WRITE file name:", event->name); printf("%s",log_buf); } else if(event->len && (event->mask & IN_MOVED_FROM)) { snprintf(log_buf, sizeof(log_buf) - 1, "%s/%s\n", "IN_MOVED_FROM file name:", event->name); printf("%s",log_buf); } i += sizeof(struct inotify_event) + event->len; } } } return 0; } int main(int argc,char *argv[]) { daemon(1, 1);// 使得程序为守护进程,脱离终端,运行在后台 signal(SIGTERM,die);//kill SIGKILL信号不能被捕获 signal(SIGINT,die);// ctrl c signal(SIGQUIT,die);// ctrl / 会产出coredump printf("watch :%s\n",argv[1]); fd = open("./watchfile.log", O_RDWR|O_CREAT|O_APPEND, 0600); /* 重定向标准输入、输出、错误到fd,就是printf将输入到fd对应的文件中 */ dup2(fd,0); dup2(fd,1); dup2(fd,2); watch_file(argv[1]); return 0; }
4、代码中使用了系统提供的创建守护进程函数
daemon(1, 1)
/*
作用 :让调用的进程变成后台进程,脱离终端,参数1,1是自定义标准输入、输出、错误
*/
5、代码中使用signal函数处理信号,当杀掉进程时在信号函数中释放一些资源
signal(SIGTERM,die);//kill 产生SIGKILL信号不能被捕获 kill -9产生的信号也不能捕捉 ,kill时也会产生SIGTERM
signal(SIGINT,die);// ctrl c 产生的信号,守护进程产生的后台进程没有作业,也接收不了ctrl c
6、代码中使用了dup2
将printf的结果输出到对应log日志中