记性是越来越差,很多学过的弄过的东西都会忘记,就从现在开始把着手过的东西稍稍记下来,方便以后看和用吧。
接触inotify是由于这次实习要做一个类似桌面搜索引擎的东西,可能会用到inotify来进行监控,就试着去了解了下,感觉还是不错的。怎么说呢,inotify还是挺容易学习和进行一些简单的操作的,无论是在终端还是应用它的API。基本的东西就不说了,差不多可以搜点别人的资料或者看inotify的首页就能有个不错的理解。简单说下就是三个主要调用。inotify_init()进行文件描述符的初始化,inotify_add_watch()用来添加监察,inotify_rm_watch()用来移出现有监察。然后监察期间所发生的事件可以通过read()函数来获取。
inotify所能监察的事件是比较完整的,但是有个缺点就是它只能监察给定的目录,而不能对该目录下的子目录有同样的功能。当然我们可以一个个添加一个要监察的目录列表,如果不多的话还是可以的,但如果有很多子目录的话就比较过分了。所以做一个递归还是比较需要的。当然,有fanotify这个东西是自带递归的,但是它所管的事件不是非常完整,当然需求不高的话可以用它。
我在网上找关于inotify递归,但没找着合适的,就只能自己修改下inotify首页给出的列子,加个递归进去。代码写的搓,就给有需要的人来个可以修改的东西吧,也当给自己这两天做的事情做个记录。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <poll.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#define EXIT_FAILURE 1;
#define EXIT_SUCCESS 0;
#define NUM_MAX 100
int fd;
int* wd = NULL;
int argc_all;
char* argv_all[NUM_MAX];
char* SubDir;
void GetSubDir(char* dir) {
DIR* dp;
struct dirent* entry;
struct stat statbuf;
if ((dp = opendir(dir)) == NULL) {
printf("can't open this directory.\n");
perror("opendir");
exit(1);
}
chdir(dir);
while ((entry = readdir(dp)) != NULL) {
char fullname[255];
asprintf(&SubDir, "%s/%s", dir, entry->d_name);
memset(fullname, 0, sizeof(fullname));
lstat(entry->d_name, &statbuf);
strncpy(fullname, dir, sizeof(fullname));
strncat(fullname, "/", sizeof(fullname));
strncat(fullname, entry->d_name, sizeof(fullname));
if (entry->d_name[0] == '.')
continue;
if (S_IFDIR & statbuf.st_mode) {
argv_all[argc_all] = SubDir;
argc_all++;
GetSubDir(fullname);
}
}
chdir("..");
closedir(dp);
}
int init_fd() { // create the file descriptor for accessing inotify API
int fd = inotify_init1(IN_NONBLOCK);
if (fd == -1) {
perror("inotify_init1");
exit(1);
}
return fd;
}
int* init_wd(int fd, int argc, char* argv[]) {// create the watch descriptor for root file
wd = (int*) calloc(argc, sizeof(int));// allocate memory for watch descriptors
if (wd == NULL) {
perror("calloc");
exit(1);
}
//printf("%d\n", argc);
for (int i = 1; i < argc; i++) {
wd[i] = inotify_add_watch(fd, argv[i], IN_ALL_EVENTS);
if (wd[i] == -1) {
fprintf(stderr, "Cannot watch '%s'\n", argv[i]);
perror("inotify_add_watch");
exit(1);
}
}
return wd;
}
static void Events_Handle(int fd, int* wd, int argc, char* argv[]) {
char buf[4096]__attribute__ ((aligned(__alignof__(struct inotify_event))));
const struct inotify_event* event;
int i;
ssize_t len;
char* ptr;
for (;;) { //read events from inotify file descriptor
len = read(fd, buf, sizeof buf);
if (len == -1 && errno != EAGAIN) {
perror("read");
exit(1);
}
if (len <= 0)
break;
for (ptr = buf; ptr < buf + len; //loop over all events in the buffer
ptr += sizeof(struct inotify_event) + event->len) {
event = (const struct inotify_event*) ptr;
char name[50];
if (event->mask & IN_ISDIR) { //print events type
strncpy(name, event->name, sizeof(name));
strncat(name, "/", sizeof(name));
printf(" [Directory: ");
for (i = 1; i < argc; i++) {
if (wd[i] == event->wd) {
printf("%s/", argv[i]);
break;
}
}
if (event->len)
printf("%s] -- ", name);
else
printf("] -- ");
if (event->mask & IN_OPEN)
printf("Directory was opened.\n");
if (event->mask & IN_CLOSE_NOWRITE)
printf("Directory was closed with no writing.\n");
if (event->mask & IN_CREATE)
printf("Directory was created.\n");
if (event->mask & IN_DELETE)
printf("Directory was deleted.\n");
if (event->mask & IN_DELETE_SELF)
printf("Directory was self deleted.\n");
if (event->mask & IN_ATTRIB)
printf("Metadata was changed.\n");
if (event->mask & IN_MOVE_SELF)
printf("Directory was self moved.\n");
if (event->mask & IN_MOVED_FROM)
printf("Old directory name when rename.\n");
if (event->mask & IN_MOVED_TO)
printf("New directory name when rename.\n");
} else {
printf(" [File: ");
for (i = 1; i < argc; i++) {
if (wd[i] == event->wd) {
printf("%s/", argv[i]);
break;
}
}
if (event->len)
printf("%s] -- ", event->name);
else
printf("] -- ");
if (event->mask & IN_OPEN)
printf("File was opened.\n");
if (event->mask & IN_ACCESS)
printf("File was accessed.\n");
if (event->mask & IN_CLOSE_WRITE)
printf("File was closed with writing.\n");
if (event->mask & IN_CLOSE_NOWRITE)
printf("File was closed with no writing.\n");
if (event->mask & IN_MODIFY)
printf("File was modified.\n");
if (event->mask & IN_CREATE)
printf("File was created.\n");
if (event->mask & IN_DELETE)
printf("File was deleted.\n");
if (event->mask & IN_DELETE_SELF)
printf("File was self deleted.\n");
if (event->mask & IN_ATTRIB)
printf("Metadata was changed.\n");
if (event->mask & IN_MOVE_SELF)
printf("File was self moved.\n");
if (event->mask & IN_MOVED_FROM)
printf("Old filename when rename.\n");
if (event->mask & IN_MOVED_TO)
printf("New filename when rename.\n");
}
}
}
}
int main(int argc, char* argv[]) {
char buf;
int poll_num;
nfds_t nfds;
struct pollfd fds[2];
argc_all = argc;
for (int i = 0; i < argc_all; i++) {
argv_all[i] = argv[i];
}
//define the Usage
if (argc_all < 2) {
printf("Usage: %s DIRECTORY [DIRECTORY]\n", argv_all[0]);
exit(1);
}
//initialize file descriptors and watch descriptors of the directory, including the sub-directories
for (int i = 1; i < argc; i++) {
GetSubDir(argv[i]);
}
fd = init_fd();
wd = init_wd(fd, argc_all, argv_all);
//prepare for polling
nfds = 2;
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
fds[1].fd = fd;
fds[1].events = POLLIN;
//wait for events and/or terminal input
printf("----------Listening begins now----------\n");
printf("----------Press ENTER to terminate----------\n");
printf("\n%s -- [Root Directory Watched]\n\n", argv_all[1]);
while (1) {
poll_num = poll(fds, nfds, -1);
if (poll_num == -1) {
if (errno == EINTR)
continue;
perror("poll");
exit(1);
}
if (poll_num > 0) {
if (fds[0].revents & POLLIN) {
while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
continue;
break;
}
if (fds[1].revents & POLLIN) {
Events_Handle(fd, wd, argc_all, argv_all);
}
}
}
printf("----------Listing for events stopped----------\n");
//close inotify file descriptor and release memory
close(fd);
free(wd);
free(SubDir);
exit(0);
}