inotify: refactored low-level functionality to inotify-backend module
This commit is contained in:
parent
2d5f94374c
commit
15649db953
5 changed files with 261 additions and 73 deletions
|
|
@ -27,9 +27,14 @@ obj-rbtree = src/rbtree.o $(obj-xalloc)
|
||||||
obj-tree = src/tree.o $(obj-xalloc)
|
obj-tree = src/tree.o $(obj-xalloc)
|
||||||
obj-fscrawl = src/fscrawl.o $(obj-strbuf) $(obj-path) $(obj-log)
|
obj-fscrawl = src/fscrawl.o $(obj-strbuf) $(obj-path) $(obj-log)
|
||||||
obj-log = src/log.o $(obj-strbuf) $(obj-xalloc)
|
obj-log = src/log.o $(obj-strbuf) $(obj-xalloc)
|
||||||
|
|
||||||
|
# inotify
|
||||||
|
obj-inotify-backend = src/inotify-backend.o $(obj-log)
|
||||||
obj-inotify-watch = src/inotify-watch.o $(obj-tree)
|
obj-inotify-watch = src/inotify-watch.o $(obj-tree)
|
||||||
obj-inotify-map = src/inotify-map.o $(obj-inotify-watch) $(obj-path) $(obj-rbtree) $(obj-list)
|
obj-inotify-map = src/inotify-map.o $(obj-inotify-watch) $(obj-path) $(obj-rbtree) $(obj-list)
|
||||||
obj-notify = src/event.o src/queue.o src/inotify.o $(obj-inotify-map) $(obj-xalloc) $(obj-fscrawl) $(obj-rbtree)
|
obj-inotify = src/inotify.o src/queue.o $(obj-inotify-backend) $(obj-inotify-map)
|
||||||
|
|
||||||
|
obj-notify = src/event.o $(obj-inotify) $(obj-xalloc) $(obj-fscrawl)
|
||||||
obj-ini = lib/ini/iniparser.o lib/ini/dictionary.o
|
obj-ini = lib/ini/iniparser.o lib/ini/dictionary.o
|
||||||
obj-mongo = src/database/mongo.o $(obj-path) $(obj-ini)
|
obj-mongo = src/database/mongo.o $(obj-path) $(obj-ini)
|
||||||
obj-mysql = src/database/mysql.o $(obj-ini) $(obj-xalloc)
|
obj-mysql = src/database/mysql.o $(obj-ini) $(obj-xalloc)
|
||||||
|
|
|
||||||
93
src/inotify-backend.c
Normal file
93
src/inotify-backend.c
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* inotify-backend.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2011 Henrik Hautakoski <henrik@fiktivkod.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include "inotify-backend.h"
|
||||||
|
#include "inotify-syscalls.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#define WATCH_MASK (IN_MOVE | IN_CREATE | IN_DELETE | IN_ONLYDIR)
|
||||||
|
|
||||||
|
static int fd = -1;
|
||||||
|
|
||||||
|
static unsigned inotify_qsize = 256;
|
||||||
|
|
||||||
|
int inotify_backend_init(void) {
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
fd = inotify_init();
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inotify_backend_exit(void) {
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inotify_backend_watch(const char *path) {
|
||||||
|
|
||||||
|
int wd = inotify_add_watch(fd, path, WATCH_MASK);
|
||||||
|
|
||||||
|
if (wd < 0) {
|
||||||
|
if (errno != EACCES && errno != ENOTDIR)
|
||||||
|
logerrno(LOG_CRIT, "inotify_watch", errno);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return wd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inotify_backend_ignore(int wd) {
|
||||||
|
|
||||||
|
if (inotify_rm_watch(fd, wd) < 0) {
|
||||||
|
logerrno(LOG_CRIT, "intotify_ignore", errno);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_PENDING 5
|
||||||
|
#define THROTTLE_SLEEP_NS 2000000
|
||||||
|
#define UPPER_BOUND(size) ((unsigned) (size) >> 1)
|
||||||
|
|
||||||
|
int inotify_backend_read(void *buf, size_t size) {
|
||||||
|
|
||||||
|
struct timespec tres = { 0, THROTTLE_SLEEP_NS };
|
||||||
|
unsigned short tcount;
|
||||||
|
unsigned int ioready = 0;
|
||||||
|
|
||||||
|
for(tcount = 0; tcount < MAX_PENDING; tcount++) {
|
||||||
|
|
||||||
|
unsigned int events;
|
||||||
|
|
||||||
|
if (ioctl(fd, FIONREAD, &ioready) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
events = ioready / IN_EVENT_SIZE;
|
||||||
|
if (events > UPPER_BOUND(inotify_qsize))
|
||||||
|
goto do_read;
|
||||||
|
|
||||||
|
nanosleep(&tres, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioready)
|
||||||
|
goto do_read;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
do_read:
|
||||||
|
return read(fd, buf, size);
|
||||||
|
}
|
||||||
78
src/inotify-backend.h
Normal file
78
src/inotify-backend.h
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
/* inotify-backend.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2010-2011 Henrik Hautakoski <henrik@fiktivkod.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __INOTIFY_BACKEND
|
||||||
|
#define __INOTIFY_BACKEND
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IN_EVENT_SIZE (sizeof(struct inotify_event) + 0x40)
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
|
||||||
|
int inotify_backend_init(void);
|
||||||
|
|
||||||
|
void inotify_backend_exit(void);
|
||||||
|
|
||||||
|
int inotify_backend_watch(const char *path);
|
||||||
|
|
||||||
|
int inotify_backend_ignore(int wd);
|
||||||
|
|
||||||
|
int inotify_backend_read(void *buf, size_t size);
|
||||||
|
|
||||||
|
#endif /* __INOTIFY_BACKEND */
|
||||||
67
src/inotify-syscalls.h
Normal file
67
src/inotify-syscalls.h
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef _LINUX_INOTIFY_SYSCALLS_H
|
||||||
|
#define _LINUX_INOTIFY_SYSCALLS_H
|
||||||
|
|
||||||
|
#include <asm/types.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
# define __NR_inotify_init 291
|
||||||
|
# define __NR_inotify_add_watch 292
|
||||||
|
# define __NR_inotify_rm_watch 293
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
# define __NR_inotify_init 253
|
||||||
|
# define __NR_inotify_add_watch 254
|
||||||
|
# define __NR_inotify_rm_watch 255
|
||||||
|
#elif defined(__alpha__)
|
||||||
|
# define __NR_inotify_init 444
|
||||||
|
# define __NR_inotify_add_watch 445
|
||||||
|
# define __NR_inotify_rm_watch 446
|
||||||
|
#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
|
||||||
|
# define __NR_inotify_init 275
|
||||||
|
# define __NR_inotify_add_watch 276
|
||||||
|
# define __NR_inotify_rm_watch 277
|
||||||
|
#elif defined(__sparc__) || defined (__sparc64__)
|
||||||
|
# define __NR_inotify_init 151
|
||||||
|
# define __NR_inotify_add_watch 152
|
||||||
|
# define __NR_inotify_rm_watch 156
|
||||||
|
#elif defined (__ia64__)
|
||||||
|
# define __NR_inotify_init 1277
|
||||||
|
# define __NR_inotify_add_watch 1278
|
||||||
|
# define __NR_inotify_rm_watch 1279
|
||||||
|
#elif defined (__s390__) || defined (__s390x__)
|
||||||
|
# define __NR_inotify_init 284
|
||||||
|
# define __NR_inotify_add_watch 285
|
||||||
|
# define __NR_inotify_rm_watch 286
|
||||||
|
#elif defined (__arm__)
|
||||||
|
# define __NR_inotify_init 316
|
||||||
|
# define __NR_inotify_add_watch 317
|
||||||
|
# define __NR_inotify_rm_watch 318
|
||||||
|
#elif defined (__SH4__)
|
||||||
|
# define __NR_inotify_init 290
|
||||||
|
# define __NR_inotify_add_watch 291
|
||||||
|
# define __NR_inotify_rm_watch 292
|
||||||
|
#elif defined (__SH5__)
|
||||||
|
# define __NR_inotify_init 318
|
||||||
|
# define __NR_inotify_add_watch 319
|
||||||
|
# define __NR_inotify_rm_watch 320
|
||||||
|
#else
|
||||||
|
# error "Unsupported architecture"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int inotify_init(void) {
|
||||||
|
|
||||||
|
return syscall(__NR_inotify_init);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int inotify_add_watch(int fd, const char *name, __u32 mask) {
|
||||||
|
|
||||||
|
return syscall(__NR_inotify_add_watch, fd, name, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int inotify_rm_watch(int fd, __u32 wd) {
|
||||||
|
|
||||||
|
return syscall(__NR_inotify_rm_watch, fd, wd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _LINUX_INOTIFY_SYSCALLS_H */
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <time.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/inotify.h>
|
|
||||||
|
|
||||||
|
#include "inotify-backend.h"
|
||||||
#include "inotify-map.h"
|
#include "inotify-map.h"
|
||||||
#include "inotify-watch.h"
|
#include "inotify-watch.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
|
@ -28,12 +26,6 @@
|
||||||
#include "fscrawl.h"
|
#include "fscrawl.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
typedef struct inotify_event inoev;
|
|
||||||
|
|
||||||
#define INOBUFSIZE ((1 << 12) * (sizeof(inoev) + 0x40))
|
|
||||||
|
|
||||||
#define WATCH_MASK (IN_MOVE | IN_CREATE | IN_DELETE | IN_ONLYDIR)
|
|
||||||
|
|
||||||
static int init = 0;
|
static int init = 0;
|
||||||
|
|
||||||
/* Inotify file descriptor */
|
/* Inotify file descriptor */
|
||||||
|
|
@ -41,17 +33,12 @@ static int fd;
|
||||||
|
|
||||||
static queue_t event_queue;
|
static queue_t event_queue;
|
||||||
|
|
||||||
static int inotify_watch(const char *path) {
|
static int watch(const char *path) {
|
||||||
|
|
||||||
int wd = inotify_add_watch(fd, path, WATCH_MASK);
|
int wd = inotify_backend_watch(path);
|
||||||
|
|
||||||
if (wd < 0) {
|
|
||||||
if (errno != EACCES && errno != ENOTDIR)
|
|
||||||
logerrno(LOG_CRIT, "inotify_watch", errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inotify_map(wd, path);
|
if (wd >= 0)
|
||||||
|
inotify_map(wd, path);
|
||||||
|
|
||||||
return wd;
|
return wd;
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +51,7 @@ static int addwatch(const char *path, const char *name) {
|
||||||
if (!npath)
|
if (!npath)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (inotify_watch(npath) < 0)
|
if (watch(npath) < 0)
|
||||||
goto clean;
|
goto clean;
|
||||||
|
|
||||||
f = fsc_open(npath);
|
f = fsc_open(npath);
|
||||||
|
|
@ -88,7 +75,7 @@ static int addwatch(const char *path, const char *name) {
|
||||||
if (ent->dir) {
|
if (ent->dir) {
|
||||||
char *fullpath = path_normalize(ev->path, ev->filename, 1);
|
char *fullpath = path_normalize(ev->path, ev->filename, 1);
|
||||||
if (fullpath) {
|
if (fullpath) {
|
||||||
if (inotify_watch(fullpath) < 0) {
|
if (watch(fullpath) < 0) {
|
||||||
xfree(fullpath);
|
xfree(fullpath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +123,7 @@ static int rmwatch(const char *path, const char *name) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proc_event(inoev *iev) {
|
static void proc_event(struct inotify_event *iev) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
struct list *watch_list;
|
struct list *watch_list;
|
||||||
|
|
@ -199,10 +186,7 @@ int notify_init() {
|
||||||
if (init)
|
if (init)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fd = inotify_init();
|
inotify_backend_init();
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
event_queue = queue_init();
|
event_queue = queue_init();
|
||||||
|
|
||||||
|
|
@ -217,8 +201,6 @@ void notify_exit() {
|
||||||
|
|
||||||
if (!init)
|
if (!init)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
inotify_unmap_all();
|
inotify_unmap_all();
|
||||||
|
|
||||||
|
|
@ -248,61 +230,24 @@ int notify_rm_watch(const char *path) {
|
||||||
return rmwatch(path, NULL);
|
return rmwatch(path, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_event* notify_read() {
|
#define BUFSZ (IN_EVENT_SIZE * (1 << 10))
|
||||||
|
|
||||||
/* bytes ready on the inotify descriptor */
|
notify_event* notify_read() {
|
||||||
int ioready;
|
|
||||||
|
|
||||||
if (!init)
|
if (!init)
|
||||||
die("inotify is not instantiated.");
|
die("inotify is not instantiated.");
|
||||||
|
|
||||||
/* if we don't have pending events, wait for more data on fd */
|
|
||||||
if (queue_isempty(event_queue)) {
|
if (queue_isempty(event_queue)) {
|
||||||
|
|
||||||
/* time resolution */
|
char buf[BUFSZ];
|
||||||
struct timespec tres = { 0, 2000000 };
|
int offset = 0, read = inotify_backend_read(buf, BUFSZ);
|
||||||
|
|
||||||
unsigned short tcount;
|
while(read > offset) {
|
||||||
|
struct inotify_event *ev = (struct inotify_event*) &buf[offset];
|
||||||
for(tcount = 0; tcount < 10; tcount++) {
|
proc_event(ev);
|
||||||
|
offset += sizeof(struct inotify_event) + ev->len;
|
||||||
if (ioctl(fd, FIONREAD, &ioready) == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ioready > INOBUFSIZE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
nanosleep(&tres, NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* otherwise, only read if the data available at
|
|
||||||
this given moment is "large enough" */
|
|
||||||
else {
|
|
||||||
ioctl(fd, FIONREAD, &ioready);
|
|
||||||
|
|
||||||
if (ioready < INOBUFSIZE / 2)
|
|
||||||
ioready = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(ioready > 0) {
|
|
||||||
|
|
||||||
char buf[INOBUFSIZE];
|
|
||||||
int offset = 0, rbytes = read(fd, buf, INOBUFSIZE);
|
|
||||||
|
|
||||||
logmsg(LOG_DEBUG, "%i bytes avail", ioready);
|
|
||||||
|
|
||||||
if (rbytes == -1) {
|
|
||||||
logerrno(LOG_WARN, "INOTIFY", errno);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(rbytes > offset) {
|
|
||||||
inoev *rev = (inoev *) &buf[offset];
|
|
||||||
proc_event(rev);
|
|
||||||
offset += sizeof(inoev) + rev->len;
|
|
||||||
}
|
|
||||||
ioready -= rbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return queue_dequeue(event_queue);
|
return queue_dequeue(event_queue);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue