使用FAM来监视linux文件系统变化

FAM(File Alteration Monitor),提供了另一种监视linux系统变化的机制。fam由两部分构成:famd,用以监听客户请求并在文件系统变化后提供通知的daemon进程;libfam,客户端应用程序与famd交互的接口。

FAM支持的文件系统事件有

  • FAMChanged,文件/文件夹被改变
  • FAMDeleted,被监视的文件/文件夹被删除。如果开始监控的不存在的路径,也会产生该事件。
  • FAMStartExecuting,被监控的可执行文件开始执行。如果多个进程执行该文件,只在第一个进程产生该事件。
  • FAMStopExecuting,文件结束执行。如果多个进程执行该文件,只在最后一个结束的进程产生该事件。
  • FAMCreated,被监视目录中有文件被创建。被监视目录的子目录改变不会被自动监视。
  • FAMMoved,该事件不会发生,定义只是为了向后兼容。
  • FAMAcknowledge,在FAMCancelMonitor()调用后famd会产生该事件;或者路径不合法(指采用了相对路径)也会产生该事件。
  • FAMExists,如果监控的一个文件,famd为该文件产生FAMExists事件;如果监控的是目录,famd为该目录和直接包含于该目录中的文件或目录产生FAMExists事件。
  • FAMEndExist,在最后一个FAMExists事件后,famd会产生FAMEndExist事件。


使用FAM的基本步骤:
1、通过调用FAMOpen创建与famd的连接,这个调用会返回一个FAMConnection结构,用于以后的函数调用。

int FAMOpen(FAMConnection* fc);

2、调用FAMMonitorDirectory或者FAMMonitorFile来监视文件或目录

int FAMMonitorDirectory(FAMConnection *fc,
        char *filename,
        FAMRequest* fr,
        void* userData);
int FAMMonitorFile(FAMConnection *fc,
        char *filename,
        FAMRequest* fr,
        void* userData);

这两个函数返回的FAMRequest结构可以用于取消、暂停或继续对文件的监控。
3、有两种方式用于检测到文件/文件夹的变化:(1)对FAMOpen返回的FAMConnection结构的文件描述符(可以通过FAMCONNECTION_GETFD宏获得)执行select调用,在可用时调用FAMNextEvent来取得FAM事件(2)周期性的调用FAMPending,如果有事件会马上返回1,否则马上返回0,在有事件时调用FAMNextEvent来取得事件。

int FAMNextEvent(FAMConnection *fc, FAMEvent *fe);
int FAMPending(FAMConnection* fc);

与FAMPending不同,FAMNextEvent在没有事件时会一直阻塞。
FAMEvent的结构为:

typedef struct {
    FAMConnection* fc;
    FAMRequest fr;
    char hostname[MAXHOSTNAMELEN];
    char filename[NAME_MAX];
    void *userdata;
    FAMCodes code;
} FAMEvent;

4、调用FAMSuspendMonitor、FAMResumeMonitor、FAMCancelMonitor来暂停、继续和取消对文件/目录的监控。

int FAMSuspendMonitor(FAMConnection *fc, FAMRequest *fr);
int FAMResumeMonitor(FAMConnection *fc, FAMRequest *fr);
int FAMCancelMonitor(FAMConnection *fc, FAMRequest *fr);

5、最后在应用程序结束之前调用FAMClose,关闭与famd的连接,释放与被监控文件相关的资源。

int FAMClose(FAMConnection* fc);

有两点需要注意:

  • FAM对文件的监控是基于文件名而不是inode的,因此如果重命名或者移动该文件,FAM会报告文件被删除。
  • 调用FAMMonitorDirectory或FAMMonitorFile时的文件名应该是绝对路径,如果是相对路径,famd会忽略请求并发送FAMAcknowledge事件。


inotify比较可见FAM的事件粒度不如inotify细,而且2.6.13以后的linux内核原生的支持inotify。然后FAM的优势在于:

  • 使用FAM可以使应用程序脱离内核版本的限制,在更多的平台上工作。
  • FAM支持NFS上的文件监控。


最后是一个简单的示例:

#include  <fam.h>
#include  <stdio.h>
#include  <unistd.h>
#include  <stdlib.h>
#include  <sys/stat.h>
 
/* event_name() - return printable name of fam event code */
  
const char *event_name(int code)
{
    static const char *famevent[] = {
        "",
        "FAMChanged",
        "FAMDeleted",
        "FAMStartExecuting",
        "FAMStopExecuting",
        "FAMCreated",
        "FAMMoved",
        "FAMAcknowledge",
        "FAMExists",
        "FAMEndExist"
    };
    static char unknown_event[10];
  
    if (code < FAMChanged || code > FAMEndExist)
    {
        sprintf(unknown_event, "unknown (%d)", code);
        return unknown_event;
    }
    return famevent[code];
}
  
void main(int argc, char *argv[])
{
    int i, nmon, rc, fam_fd;
    FAMConnection fc;
    FAMRequest *frp;
    struct stat status;
    FAMEvent fe;
    fd_set readfds;
  
    /* Allocate storage for requests */
  
    frp = malloc(argc * sizeof *frp);
    if (!frp)
    {
        perror("malloc");
        exit(1);
    }
  
    /* Open fam connection */
  
    if ((FAMOpen(&fc)) < 0) 
    {
        perror("fam");
        exit(1);
    }
  
    /* Request monitoring for each program argument */
  
    for (nmon = 0, i = 1; i < argc; i++)
    {
        if (stat(argv[i], &status) < 0)
        {
            perror(argv[i]);
            status.st_mode = 0;
        }
        if ((status.st_mode & S_IFMT) == S_IFDIR)
            rc = FAMMonitorDirectory(&fc, argv[i], frp + i,
                                     NULL);
        else
            rc = FAMMonitorFile(&fc, argv[i], frp + i, NULL);
        if (rc < 0)
        {
            perror("FAMMonitor failed");
            continue;
        }
        nmon++;
    }
    if (!nmon)
    {
        fprintf(stderr, "Nothing monitored.\n");
        exit(1);
    }
  
    /* Initialize select data structure */
  
    fam_fd = FAMCONNECTION_GETFD(&fc);
    FD_ZERO(&readfds);
    FD_SET(fam_fd, &readfds);
  
    /* Loop forever. */
  
    while(1)
    {
        if (select(fam_fd + 1, &readfds,
                   NULL, NULL, NULL) < 0)
        {
             perror("select failed");
             exit(1);
        }
        if (FD_ISSET(fam_fd, &readfds))
        {
            if (FAMNextEvent(&fc, &fe) < 0)
            {
                perror("FAMNextEvent");
                exit(1);
            }
            printf("%-24s %s\n", fe.filename,
                   event_name(fe.code));
        }
    }
}

转载于:https://www.cnblogs.com/tianyapiaozi/archive/2010/04/08/2513895.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值