您的位置:首页 > 运维架构 > Linux

文件监控系统设计(3)-"Linux"

2011-08-08 15:00 495 查看
今天简单讨论下Linux下文件系统的监控方法,我测试过的有如下三种方法,分布针对不同的kernel 版本:

1 , 使用inotify API (如果你的Linux kernel >= 2.6.13 ,恭喜你了, 可以直接调用这个新的API )

2 , 使用inotify device ( 2.4.27<= kernel <= 2.6.13 , 这个方法本质上和调用inotify API 是一样的,但是麻烦些, 要给kernel打patch )

3 , 使用文件轮询方式 ( 这个不适用特别的API, 适用所有kernel版本 )

方法1 : inotify API 的使用

这个方法我实在不想在这里多说了, 网上一搜一堆得资料 。 这个方法应该是目前监控Linux 文件系统变化最佳的途径, 毕竟像文件监控这种任务能得到操作系统提供的API的支持是最好不过的了,coding 很容易, 也节省系统资源,不需要像方法3 轮询那样时刻或者定期的检查文件。

man page: http://linux.die.net/man/7/inotify
方法2 : inotify device 的使用

inotfiy API是在2.6.13 的版本之后加入kernel的, 一些国外编写linux kernel的牛人制作的一个backported的patch, 使得部分早于2.6.13 的linux系统也可以使用类似于调用inotify API方法进行文件监控。

以下两篇文章不错:
http://www.developertutorials.com/tutorials/linux/monitor-linux-inotify-050531-1133/ http://lwn.net/Articles/142751/
看完上面两篇文章之后就可以对大概如何使用inotify device 的方式监控文件有个大致的了解了,如果你觉得还想继续深究,下面这个链接提供了一些现成的源码
http://www.kernel.org/pub/linux/kernel/people/rml/inotify/utils/
其中 inotify-utils-0.21.tar.gz  值得一看, 拿来修改后可以直接使用。

方法3 :文件轮询的方法

这几天我在网上搜索了很多linux下文件监控的方法,绝大部分是推荐使用inotify API的文章,另外也有提及使用signal的方法,尚未找到使用文件轮询的方式进行文件监控的文章,这里我会较为详细的介绍下这个方法。(此方法的最大优点是没有使用任何特别的API, 适用于绝大多数Linux版本)

一 设计思路

      通过文件对比的方法检测文件的Add,Delete, Modify

二 具体步骤

2.1 文件夹拷贝: 先把需要监控的文件夹完全复制一份,最为文件对比时的参考文件夹

2.2 文件"反向"检测:

使用readdir() 依次读取参考文件夹中的每个文件: 如果读取到的时文件夹,则递归调用此函数;

如果读取到的是文件,首先检测监控文件夹中对应的文件是否存在,如果不存在了,则认为此文件在监控文件夹中被删除,触发一个Delete 的事件,如果文件存在,继续检测 last write time 是否一致,如果last write time变化了, 说明此文件被修改;

所谓"反向" 的意思是说通过依次打开参考文件夹中的所有文件,来检测监控文件夹中对应的文件是否还存在或者被修改,显然,使用"反向”检测的方式只能检测文件的Delete 和 Modify,不能检测文件的Add。检测文件的Add 要通过"正向"检测的方法。

2.2 文件"反向"检测: 使用readdir() 依次读取监控文件夹中的每个文件:如果某个文件在对应的参考文件夹中不存在,则说明此文件是新添加的。

三 注意事项

3.1 开始监控前一定要先copy 监控文件夹作为对比用的参考文件夹

3.2 不能拿参考文件夹中文件的last write time 直接和监控文件的last write time 直接对比,因为参考文件夹中的last write time 是文件夹初始被拷贝创建的时间。所有要通过某种方式在监控开始前把监控文件夹中所有文件的last write time 提前记录下来,供监控对比时使用。我使用map来存储监控文件夹中所有文件的last write time。

3.3 注意递归的使用,要遍历文件夹中所有子文件夹的内容,一定要使用递归。

3.4 参考文件夹要和监控文件夹保持实时同步,比如在某轮监控中检测到一个新添加的文件,则同时要把此文件copy到参考文件夹,或者文件被修改,则要update  map中对应的last write time。 避免下一轮检测中报告同样的事件。

四 code 

代码为3个源文件, scm.h scm_main.cpp scm.cpp 。

编译执行后可以实现对某个文件夹内文件Add, Delete, Modify事件的监控 。

注意:程序执行前先copy要监控的文件夹。 把监控文件夹和参考文件夹的path作为可执行程序的参数传入。另外还需要建立一个backup的空文件夹,程序运行时会吧删除的或者被修改的original file 存放在backup的文件夹内

头文件 scm.h

#ifndef _SCM_

#define _SCM_

#include <string>

#include <map>

#define BACKUP_DIR "/home/joshua/backup"

using namespace std;

extern char dir_mon[255];

extern char dir_bak[255];

extern map<string, time_t> modify_time;

void mon_routine ();

int dir_lookup (char *, char *, int);

void file_lookup (char *, char *, char *, int);

int mtime_init (char *);

void sys_time ();

void sys_hostname ();

#endif

主文件 scm_main.cpp

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <string.h>

#include <string>

#include <dirent.h>

#include <unistd.h>

#include <map>

#include "scm.h"

using namespace std;

char dir_mon[255]={0}; // directory to monitor

char dir_bak[255]={0};  //  directory as reference

map<string, time_t> modify_time;

int main (int argc, char **argv)

{

    // pass arguments as directory path

    memcpy(dir_mon, argv[1], strlen(argv[1]));

    memcpy(dir_bak, argv[2], strlen(argv[2]));

      

    // initialize modify_time

    if (mtime_init(dir_mon) == -1)

    {

        printf("mtime_init fail");

        return -1;

    }

    

    printf(" Monitoring begin !\n");

    while (1)

    {

        // monitor routine every 5 sec

        mon_routine ();

        sleep (5);

    }

    

    return 0;

}

函数 scm.cpp

#include <stdio.h>

#include <time.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <dirent.h>

#include <sys/ioctl.h>

#include <string>

#include <errno.h>

#include <map>

#include "scm.h"

using namespace std;

void mon_routine ()

{

// lookup from backup_dir to monitor_dir, detect file delete or modify, flag=0

    dir_lookup (dir_mon, dir_bak, 0);

// lookup from monitor_dir to backup_dir, detect file add, flag =1

    dir_lookup (dir_bak, dir_mon, 1);

    return ;

}

int dir_lookup (char *dir, char *dir_open, int flag)

{

    DIR *odir;

    struct dirent* dent;

    int len;

    

// Open  directory

    if ((odir = opendir(dir_open)) == NULL)

    {

        printf ("Dir %s ", dir_open);

        perror ("Couldn't be open:");

        return -1;

    }

// Lookup files in this directory one-by-one

    while ((dent = readdir(odir)) != NULL)

    {

    // special file "." ".."

        if ( strcmp(dent->d_name, ".") == 0 ||

             strcmp(dent->d_name, "..") == 0 )

        {

            continue;

        }

        len = strlen(dent->d_name);

    // regular file need to be checked

        if ( dent->d_type == DT_REG &&

             dent->d_name[0] != '.' &&        // get rid of hiden file

             !(dent->d_name[len-1] == 'p' &&  // get rid of temporary file

               dent->d_name[len-2] == 'm' &&

               dent->d_name[len-3] == 't' &&

               dent->d_name[len-4] == '.')&&

             dent->d_name[len-1] != '~'         // get rid of temporary file

           )

        {

            char pathname_o[255]={0};

            char pathname[255]={0};

            sprintf(pathname_o, "%s/%s", dir_open, dent->d_name);

            sprintf(pathname, "%s/%s", dir, dent->d_name);

            // check out if this file is deleted , modified or added , controlled
babf
by flag bit

            file_lookup (pathname, pathname_o, dent->d_name, flag);

        }

            

        

    // check out directory recursively

        if (dent->d_type == DT_DIR )

        {

            char subdir_open[255]={0};

            char subdir[255]={0};

            sprintf(subdir_open, "%s/%s", dir_open, dent->d_name);

            sprintf(subdir, "%s/%s", dir, dent->d_name);

            // check out if this dir exist, if not , create it

            struct stat statbuf_m;

            if (stat(subdir, &statbuf_m) == -1)

            {

                // dir does not exist, which means a dir is created

                   char cmd[255]={0};

                sprintf(cmd, "mkdir %s", subdir);

                if(system(cmd) == -1)

                {

                    perror("CMD Fail:");

                }

            }

            // directory lookup recursively, controlled by flag bit

            dir_lookup (subdir, subdir_open, flag);

        }

    }

    closedir(odir);

    return 0;

}

void file_lookup (char *file, char *file_o, char *file_name, int flag)

{

    struct stat statbuf_m;

    

    // file doesn not exist anymore

    if (stat(file, &statbuf_m) == -1 && flag == 0)

    {

        sys_time ();

        sys_hostname ();

        printf("%s was deleted!\n", file);

        

        

        // remove deleted file to backup dir

        char newpath[255]={0};

        sprintf(newpath, "%s/%s", BACKUP_DIR, file_name);

        if(rename(file_o, newpath) == -1)

        {

            perror("file backup fail:");

        }

        

        // delete the filepath in map

        modify_time.erase (file);

        return ;

    }

    

    // file was MODIFIED

    if (statbuf_m.st_mtime != modify_time[file] && flag == 0)

    {

        sys_time ();

        sys_hostname ();

        printf("%s was modified!\n", file);

        // move original file to backup dir

        char newpath[255]={0};

        sprintf(newpath, "%s/%s", BACKUP_DIR, file_name);

        if(rename(file_o, newpath) == -1)

        {

            perror("file backup fail:");

        }

        // update modify_time map

        modify_time[file] = statbuf_m.st_mtime;

        // copy modified file to sync dir

        char cmd[255]={0};

        sprintf(cmd, "cp \"%s\" \"%s\"", file, file_o);

        if (system(cmd) == -1)

        {

            perror(" Cmd fail\n");

        }

    }

    // a new file was added, this is implemented by directory check backwardly, controlled by flag bit

    if (stat(file, &statbuf_m) == -1 && flag == 1)

    {

        sys_time ();

        sys_hostname ();

        printf("%s was added!\n", file_o);

        // copy new file to sync_dir

        char cmd[255]={0};

        sprintf(cmd, "cp \"%s\" \"%s\"", file_o, file);

        if (system(cmd) == -1)

        {

            perror("CMD fail:\n");

        }

        

        // update new file mtime to map

        stat (file_o, &statbuf_m);

        modify_time[file_o] = statbuf_m.st_mtime;

    }

    

}

int mtime_init (char *dir_m)

{

    DIR *odir;

    struct dirent* dent;

    

    

// Open this backup directory

    if ((odir = opendir(dir_m)) == NULL)

    {

        printf ("Dir %s ", dir_m);

        perror ("Couldn't be open:");

        return -1;

    }

// Lookup files in this directory one-by-one

    while ((dent = readdir(odir)) != NULL)

    {

    // special file "." ".."

        if ( strcmp(dent->d_name, ".") == 0 ||

             strcmp(dent->d_name, "..") == 0 )

        {

            continue;

        }

    // record regular file last_modify_time

        if ( dent->d_type == DT_REG )

        {

            struct stat statbuf;

            char pathname_m[255]={0};

            sprintf(pathname_m, "%s/%s", dir_m, dent->d_name);

            stat (pathname_m, &statbuf);

            modify_time[pathname_m]=statbuf.st_mtime;

        }

            

        

    // check out directory recursively

        if (dent->d_type == DT_DIR )

        {

            char subdir_m[255]={0};

            sprintf(subdir_m, "%s/%s", dir_m, dent->d_name);

            if (mtime_init (subdir_m) == -1)

            {

                return -1;

            }

        }

    }

    closedir(odir);

    return 0;

}

    

void sys_time ()

{

    time_t time_now;

    struct tm *time_local;

    char tm[30]={0};

    

    time(&time_now);

    time_local = localtime (&time_now);

    sprintf(tm, "%d/%d/%d %d:%d:%d", time_local->tm_mon+1,

                     time_local->tm_mday,

                     time_local->tm_year+1900,

                     time_local->tm_hour,

                     time_local->tm_min,

                     time_local->tm_sec);

    printf ("%s", tm);

}

void sys_hostname ()

{

    char hostname[50]={0};

    gethostname (hostname, 50);

    printf (" %s ",hostname);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux file cmd delete struct api