• 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
    ");
    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	   event : %-30s	   file name : %-30s	   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
    ");
    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
    ");
    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
    ");
    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
    ");
    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 }

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

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

  • 相关阅读:
    【Log历练手册】Spring事务管理不能提交异常
    【网络安全】如何使用OpenSSL工具生成根证书与应用证书
    【网络安全】如何使用OpenSSL工具生成根证书与应用证书
    【JAVA笔记——器】Spring Aop 实现Log日志系统——基本实现
    jdbc连接池配置方法
    用于读/写配置的工具,下面列出了各种配置(从最高优先级到最低优先级)
    文件复制Util写法,可以适用于多种条件
    记录一个工作中遇到的问题,svn拉的项目,pom.xml报错
    layui的js写法,部分代码
    JDBCUtil连接数据库的写法
  • 原文地址:https://www.cnblogs.com/jiangyibo/p/8919178.html
Copyright © 2020-2023  润新知