티스토리 뷰

개발/Linux

특정 폴더 감시 inotify_add_watch()

Jaeyeon Baek 2013. 7. 23. 14:29


리눅스 프로그래밍중 특정 폴더를 감시해야 하는 경우가 있습니다.


해당 기능을 구현하기 위한 방안은 여러가지가 있는데요, 이를테면, 그 폴더의 SIGIO를 등록해서 폴더의 input/output을 감시할 수 있습니다.


하지만 이 경우에는 create / write / close / delete 등을 별도로 구분하지 못하는 부족함이 있습니다. 또한 signal의 경우 중복으로 요청이 들어올 경우 앞선 signal을 잃어버리는 경우도 발생하기 때문에 좋은 방안은 아닌듯 보이죠.. (fcntl 를 이용한 signal 처리에도 create/rename/close 등을 구분할 수는 있네요^^;)


이때 대안이 되는방법이 inotify_add_watch() 라는 함수를 사용하는 것 입니다. 일단 형태는 아래와 같습니다.

#include <sys/inotify.h>
int inotify_add_watch(int fd, const char *pathname, uint32_t mask);


세번째 인자인 mask는 감시 대상의 상태 변화를 표현합니다. 표현할 수 있는 mask에는 아래와 같습니다.

/* Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.  */
#define IN_ACCESS        0x00000001     /* File was accessed.  */
#define IN_MODIFY        0x00000002     /* File was modified.  */
#define IN_ATTRIB        0x00000004     /* Metadata changed.  */
#define IN_CLOSE_WRITE   0x00000008     /* Writtable file was closed.  */
#define IN_CLOSE_NOWRITE 0x00000010     /* Unwrittable file closed.  */
#define IN_CLOSE         (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* Close.  */
#define IN_OPEN          0x00000020     /* File was opened.  */
#define IN_MOVED_FROM    0x00000040     /* File was moved from X.  */
#define IN_MOVED_TO      0x00000080     /* File was moved to Y.  */
#define IN_MOVE          (IN_MOVED_FROM | IN_MOVED_TO) /* Moves.  */
#define IN_CREATE        0x00000100     /* Subfile was created.  */
#define IN_DELETE        0x00000200     /* Subfile was deleted.  */
#define IN_DELETE_SELF   0x00000400     /* Self was deleted.  */
#define IN_MOVE_SELF     0x00000800     /* Self was moved.  */

/* Events sent by the kernel.  */
#define IN_UNMOUNT       0x00002000     /* Backing fs was unmounted.  */
#define IN_Q_OVERFLOW    0x00004000     /* Event queued overflowed.  */
#define IN_IGNORED       0x00008000     /* File was ignored.  */

/* Helper events.  */
#define IN_CLOSE         (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)    /* Close.  */
#define IN_MOVE          (IN_MOVED_FROM | IN_MOVED_TO)          /* Moves.  */

/* Special flags.  */
#define IN_ONLYDIR       0x01000000     /* Only watch the path if it is a
                                           directory.  */
#define IN_DONT_FOLLOW   0x02000000     /* Do not follow a sym link.  */
#define IN_MASK_ADD      0x20000000     /* Add to the mask of an already
                                           existing watch.  */
#define IN_ISDIR         0x40000000     /* Event occurred against dir.  */
#define IN_ONESHOT       0x80000000     /* Only send event once.  */

/* All events which a program can wait on.  */
#define IN_ALL_EVENTS    (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE  \
                          | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM        \
                          | IN_MOVED_TO | IN_CREATE | IN_DELETE               \
                          | IN_DELETE_SELF | IN_MOVE_SELF)


자, 이제 사용방법을 살펴봅니다. inotify_add_watch() 를 사용하기 위해서는 등록이 필요하겠죠, 아래 함수를 사용합니다.

#include <sys/inotify.h>
int inotify_init(void)


연계해서 간단한 파일의 이동을 감시하는 구문을 작성해보면 아래와 같습니다.

// init
fd = inotify_init();

// 감시 PATH 등록
wd = inotify_add_watch(fd, PATH, IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVED_TO | IN_CLOSE ...);

length = read( fd, buffer, BUF_LEN ); 
while ( i < length ) {
  struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
  if ( event->len ) {
    if ( event->mask & IN_MOVED_TO) { // 해당 조건처럼 & 연산을 통해 else if 추가 등록
      if ( event->mask & IN_ISDIR ) {
        printf("The directory %s was move.\n", event->name );
      }   
      else {
        printf("The file %s was move.\n", event->name );
      }   
    }      
    i += EVENT_SIZE + event->len;
  }
}


inotify_event 구조체를 통해 파일의 이름 등 알수 있는 정보가 다양한데, 구조체는 아래와 같습니다.

/* Structure describing an inotify event.  */
struct inotify_event
{
  int wd;               /* Watch descriptor.  */
  uint32_t mask;        /* Watch mask.  */
  uint32_t cookie;      /* Cookie to synchronize two events.  */
  uint32_t len;         /* Length (including NULs) of name.  */
  char name __flexarr;  /* Name.  */
};



이제 inotify_add_watch()의 사용으로 특정 폴더의 상태 변화를 감지할 수 있는 코드를 작성 할 수 있습니다.


단, 커널에 아래 옵션이 활성화 되어 있어야 합니다.

CONFIG_INOTIFY=y

CONFIG_INOTIFY_USER=y

(커널 2.6.13 이상 부터 지원)


댓글
댓글쓰기 폼