sleepy_penguin RubyGem user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* [PATCH (WIP)] FANotify support
@ 2011-07-27  0:32 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2011-07-27  0:32 UTC (permalink / raw)
  To: sleepy.penguin

I started working on this a few weeks ago but don't know when I'll
have a chance to finish it, so I'm throwing it up here in case
somebody wants to play with it and get it usable.

fanotify lacks manpages, even, and the LWN articles are for an older API
so it'll require some reading of kernel/glibc sources to get it
working...

---
 ext/sleepy_penguin/extconf.rb |    1 +
 ext/sleepy_penguin/fanotify.c |  168 +++++++++++++++++++++++++++++++++++++++++
 ext/sleepy_penguin/init.c     |    7 ++
 test/test_fanotify.rb         |   20 +++++
 4 files changed, 196 insertions(+), 0 deletions(-)
 create mode 100644 ext/sleepy_penguin/fanotify.c
 create mode 100644 test/test_fanotify.rb

diff --git a/ext/sleepy_penguin/extconf.rb b/ext/sleepy_penguin/extconf.rb
index ba1db75..d8b6523 100644
--- a/ext/sleepy_penguin/extconf.rb
+++ b/ext/sleepy_penguin/extconf.rb
@@ -6,6 +6,7 @@ have_header('sys/signalfd.h')
 have_header('sys/timerfd.h')
 have_header('sys/inotify.h')
 have_header('sys/signalfd.h')
+have_header('sys/fanotify.h')
 have_header('ruby/io.h') and have_struct_member('rb_io_t', 'fd', 'ruby/io.h')
 have_func('epoll_create1', %w(sys/epoll.h))
 have_func('rb_thread_blocking_region')
diff --git a/ext/sleepy_penguin/fanotify.c b/ext/sleepy_penguin/fanotify.c
new file mode 100644
index 0000000..ccd46d5
--- /dev/null
+++ b/ext/sleepy_penguin/fanotify.c
@@ -0,0 +1,168 @@
+#ifdef HAVE_SYS_FANOTIFY_H
+#include "sleepy_penguin.h"
+#include <sys/fanotify.h>
+static VALUE cEventMetadata, cResponse;
+static VALUE sym_AT_FDCWD;
+
+static VALUE response_fd_m(VALUE self)
+{
+	struct fanotify_response *response = DATA_PTR(self);
+
+	return INT2NUM(response->fd);
+}
+
+static VALUE response_response_m(VALUE self)
+{
+	struct fanotify_response *response = DATA_PTR(self);
+
+	return UINT2NUM(response->response);
+}
+
+/*
+struct fanotify_event_metadata {
+	__u32 event_len;
+	__u8 vers;
+	__u8 reserved;
+	__u16 metadata_len;
+	__aligned_u64 mask;
+	__s32 fd;
+	__s32 pid;
+};
+*/
+
+static VALUE s_new(int argc, VALUE *argv, VALUE klass)
+{
+	VALUE flags, event_f_flags, rv;
+	struct {
+		unsigned int flags;
+		unsigned int event_f_flags;
+	} a;
+	int fd;
+
+	rb_scan_args(argc, argv, "02", &flags, &event_f_flags);
+	a.flags = NIL_P(flags) ? 0 : NUM2UINT(flags);
+	a.event_f_flags = NIL_P(event_f_flags) ? 0 : NUM2UINT(event_f_flags);
+
+	fd = fanotify_init(a.flags, a.event_f_flags);
+	if (fd == -1) {
+		if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
+			rb_gc();
+			fd = fanotify_init(a.flags, a.event_f_flags);
+		}
+		if (fd == -1)
+			rb_sys_fail("fanotify_init");
+	}
+
+	rv = INT2FIX(fd);
+	return rb_call_super(1, &rv);
+}
+
+struct mark_args {
+	int fanotify_fd;
+	unsigned flags;
+	uint64_t mask;
+	int dfd;
+	const char *pathname;
+};
+
+/* Add, remove, or modify an fanotify mark on a filesystem object.  */
+/* extern int fanotify_mark (int fanotify_fd, unsigned int flags, */
+			  /* uint64_t mask, int dfd, const char *pathname) */
+static VALUE mark(VALUE self)
+{
+	struct mark_args args;
+
+	/* StringValueCStr() */
+
+	return self;
+}
+
+static VALUE event_metadata_alloc(VALUE klass)
+{
+	struct fanotify_event_metadata *em;
+
+	em = ALLOC(struct fanotify_event_metadata);
+
+	return Data_Wrap_Struct(klass, NULL, -1, em);
+}
+
+static VALUE response_alloc(VALUE klass)
+{
+	struct fanotify_response *response = ALLOC(struct fanotify_response);
+
+	return Data_Wrap_Struct(klass, NULL, -1, response);
+}
+
+void sleepy_penguin_init_fanotify(void)
+{
+	VALUE mSleepyPenguin, cFanotify;
+
+	mSleepyPenguin = rb_define_module("SleepyPenguin");
+	cFanotify = rb_define_class_under(mSleepyPenguin, "Fanotify", rb_cIO);
+	rb_define_singleton_method(cFanotify, "new", s_new, -1);
+	return;
+
+#define FAN(x) rb_define_const(cFanotify,#x,UINT2NUM(FAN_##x))
+	FAN(ACCESS);
+	FAN(MODIFY);
+	FAN(CLOSE_WRITE);
+	FAN(CLOSE_NOWRITE);
+	FAN(OPEN);
+	FAN(Q_OVERFLOW);
+	FAN(OPEN_PERM);
+	FAN(ACCESS_PERM);
+	FAN(ONDIR);
+	FAN(EVENT_ON_CHILD);
+	FAN(CLOSE);
+	FAN(CLOEXEC);
+	FAN(CLASS_NOTIF);
+	FAN(CLASS_CONTENT);
+	FAN(CLASS_PRE_CONTENT);
+	FAN(ALL_CLASS_BITS);
+	FAN(UNLIMITED_QUEUE);
+	FAN(UNLIMITED_MARKS);
+	FAN(ALL_INIT_FLAGS);
+	FAN(MARK_ADD);
+	FAN(MARK_REMOVE);
+	FAN(MARK_DONT_FOLLOW);
+	FAN(MARK_ONLYDIR);
+	FAN(MARK_MOUNT);
+	FAN(MARK_IGNORED_MASK);
+	FAN(MARK_IGNORED_SURV_MODIFY);
+	FAN(MARK_FLUSH);
+	FAN(ALL_MARK_FLAGS);
+	FAN(ALL_EVENTS);
+	FAN(ALL_PERM_EVENTS);
+	FAN(ALL_OUTGOING_EVENTS);
+
+	rb_define_const(cFanotify, "METADATA_VERSION",
+	                INT2NUM(FANOTIFY_METADATA_VERSION));
+
+	/* Legit userspace responses to a _PERM event */
+	FAN(ALLOW);
+	FAN(DENY);
+
+	rb_define_const(cFanotify, "NOFD", INT2FIX(-1));
+
+	rb_define_alloc_func(cResponse, response_alloc);
+	rb_define_method(cResponse, "fd", response_fd_m, 0);
+	rb_define_method(cResponse, "response", response_response_m, 0);
+
+	rb_define_alloc_func(cEventMetadata, event_metadata_alloc);
+
+	sym_AT_FDCWD = ID2SYM(rb_intern("AT_FDCWD"));
+}
+
+/* Helper functions to deal with fanotify_event_metadata buffers */
+#if 0
+#define FAN_EVENT_METADATA_LEN
+
+#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \
+				   (struct fanotify_event_metadata*)(((char *)(meta)) + \
+				   (meta)->event_len))
+
+#define FAN_EVENT_OK(meta, len)	((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \
+				(long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
+				(long)(meta)->event_len <= (long)(len))
+#endif
+#endif /* HAVE_SYS_FANOTIFY_H */
diff --git a/ext/sleepy_penguin/init.c b/ext/sleepy_penguin/init.c
index eea0025..24a23b0 100644
--- a/ext/sleepy_penguin/init.c
+++ b/ext/sleepy_penguin/init.c
@@ -24,6 +24,12 @@ void sleepy_penguin_init_signalfd(void);
 #  define sleepy_penguin_init_signalfd() for(;0;)
 #endif
 
+#ifdef HAVE_SYS_FANOTIFY_H
+void sleepy_penguin_init_fanotify(void);
+#else
+#  define sleepy_penguin_init_fanotify() for(;0;)
+#endif
+
 void Init_sleepy_penguin_ext(void)
 {
 	sleepy_penguin_init_epoll();
@@ -31,4 +37,5 @@ void Init_sleepy_penguin_ext(void)
 	sleepy_penguin_init_eventfd();
 	sleepy_penguin_init_inotify();
 	sleepy_penguin_init_signalfd();
+	sleepy_penguin_init_fanotify();
 }
diff --git a/test/test_fanotify.rb b/test/test_fanotify.rb
new file mode 100644
index 0000000..80ae6c6
--- /dev/null
+++ b/test/test_fanotify.rb
@@ -0,0 +1,20 @@
+require 'test/unit'
+require 'fcntl'
+require 'tempfile'
+require 'set'
+$-w = true
+require 'sleepy_penguin'
+
+class TestFanotify < Test::Unit::TestCase
+  include SleepyPenguin
+
+  def teardown
+    ObjectSpace.each_object(Fanotify) { |io| io.close unless io.closed? }
+    ObjectSpace.each_object(Tempfile) { |io| io.close unless io.closed? }
+  end
+
+  def test_new
+    @fan = Fanotify.new
+    assert_kind_of(IO, @fan)
+  end
+end
-- 
Eric Wong


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2011-07-27  0:32 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-27  0:32 [PATCH (WIP)] FANotify support Eric Wong

Code repositories for project(s) associated with this public inbox

	https://yhbt.net/sleepy_penguin.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).