在工作中对应需要将产生的日志文件进行显示,用到监控文件系统事件的一些函数,整理下笔记。

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日志中