aboutsummaryrefslogtreecommitdiffstats
path: root/devel
diff options
context:
space:
mode:
authormarcus <marcus@FreeBSD.org>2005-04-02 17:08:47 +0800
committermarcus <marcus@FreeBSD.org>2005-04-02 17:08:47 +0800
commitcbce0154028b1d5255d24bf909ad6189b9ea2079 (patch)
tree9a34113ed8e56803587836136f6c6269fdd153ee /devel
parente3615345b74e1c20ccb2fc3f0417e5c7d4de5ddf (diff)
downloadfreebsd-ports-gnome-cbce0154028b1d5255d24bf909ad6189b9ea2079.tar.gz
freebsd-ports-gnome-cbce0154028b1d5255d24bf909ad6189b9ea2079.tar.zst
freebsd-ports-gnome-cbce0154028b1d5255d24bf909ad6189b9ea2079.zip
Add gamin, a file and directory monitoring server and API. Gamin can be
used as a drop-in replacement for FAM. Gamin is designed to be more secure than FAM as itdoes not require RPC, and runs a separate instance for each user. While it is API and ABI compatible with FAM, it does not [yet] support all of FAM's features. This version of gamin comes with an optional (defaults to on) kqueue backend for FreeBSD. This backend can only be used with UFS file systems. If you need FAM-like support on non-UFS file systems, you must build without the kqueue backend.
Diffstat (limited to 'devel')
-rw-r--r--devel/Makefile1
-rw-r--r--devel/gamin/Makefile45
-rw-r--r--devel/gamin/distinfo2
-rw-r--r--devel/gamin/files/patch-config.h.in12
-rw-r--r--devel/gamin/files/patch-configure76
-rw-r--r--devel/gamin/files/patch-configure.in31
-rw-r--r--devel/gamin/files/patch-libgamin_gam_api.c98
-rw-r--r--devel/gamin/files/patch-python_Makefile.in32
-rw-r--r--devel/gamin/files/patch-server_Makefile.in47
-rw-r--r--devel/gamin/files/patch-server_gam_channel.c127
-rw-r--r--devel/gamin/files/patch-server_gam_kqueue.c639
-rw-r--r--devel/gamin/files/patch-server_gam_kqueue.h27
-rw-r--r--devel/gamin/files/patch-server_gam_server.c56
-rw-r--r--devel/gamin/pkg-descr5
-rw-r--r--devel/gamin/pkg-plist10
15 files changed, 1208 insertions, 0 deletions
diff --git a/devel/Makefile b/devel/Makefile
index a19ce01e3d7b..3ad51c1b372b 100644
--- a/devel/Makefile
+++ b/devel/Makefile
@@ -271,6 +271,7 @@
SUBDIR += g-wrap
SUBDIR += g2c
SUBDIR += gaa
+ SUBDIR += gamin
SUBDIR += gaphor
SUBDIR += gauche-gaunit
SUBDIR += gauche-readline
diff --git a/devel/gamin/Makefile b/devel/gamin/Makefile
new file mode 100644
index 000000000000..1bf34abb76b0
--- /dev/null
+++ b/devel/gamin/Makefile
@@ -0,0 +1,45 @@
+# ports collection makefile for: gamin
+# Date created: 24 March 2005
+# Whom: Joe Marcus Clarke <marcus@FreeBSD.org>
+#
+# $FreeBSD$
+#
+
+PORTNAME= gamin
+PORTVERSION= 0.0.26
+PORTREVISION?= 8
+CATEGORIES?= devel
+MASTER_SITES= http://www.gnome.org/~veillard/gamin/sources/
+
+MAINTAINER?= gnome@FreeBSD.org
+COMMENT?= A file and directory monitoring system
+
+USE_GMAKE= yes
+USE_LIBTOOL_VER=15
+USE_GNOME?= gnomehack glib20
+INSTALLS_SHLIB= yes
+CONFIGURE_ARGS?=--disable-gtk-doc --with-html-dir=${PREFIX}/share/doc \
+ --without-python
+CONFIGURE_ENV= CPPFLAGS="-I${LOCALBASE}/include" \
+ LDFLAGS="-L${LOCALBASE}/lib"
+
+CONFLICTS= fam-[0-9]*
+
+.if !defined(GAMIN_SLAVE)
+OPTIONS= KQUEUE "Enable the KQueue backend (UFS only)" on
+.endif
+
+.include <bsd.port.pre.mk>
+
+.if !defined(GAMIN_SLAVE)
+.if defined(WITHOUT_KQUEUE)
+CONFIGURE_ARGS+= --disable-kqueue
+.else
+CONFIGURE_ARGS+= --enable-kqueue
+.endif
+.endif
+
+post-patch:
+ @${FIND} ${WRKSRC} -type f | ${XARGS} ${TOUCH} -f
+
+.include <bsd.port.post.mk>
diff --git a/devel/gamin/distinfo b/devel/gamin/distinfo
new file mode 100644
index 000000000000..498f60829967
--- /dev/null
+++ b/devel/gamin/distinfo
@@ -0,0 +1,2 @@
+MD5 (gamin-0.0.26.tar.gz) = 3d716b6533466f9ca69df13c58009981
+SIZE (gamin-0.0.26.tar.gz) = 484070
diff --git a/devel/gamin/files/patch-config.h.in b/devel/gamin/files/patch-config.h.in
new file mode 100644
index 000000000000..095ee06375ee
--- /dev/null
+++ b/devel/gamin/files/patch-config.h.in
@@ -0,0 +1,12 @@
+--- config.h.in.orig Thu Mar 24 23:41:54 2005
++++ config.h.in Thu Mar 24 23:42:12 2005
+@@ -6,6 +6,9 @@
+ /* Use inotify as backend */
+ #undef ENABLE_INOTIFY
+
++/* Use kqueue as backend */
++#undef ENABLE_KQUEUE
++
+ /* Use polling as backend */
+ #undef ENABLE_POLLING
+
diff --git a/devel/gamin/files/patch-configure b/devel/gamin/files/patch-configure
new file mode 100644
index 000000000000..c26ef854cf2e
--- /dev/null
+++ b/devel/gamin/files/patch-configure
@@ -0,0 +1,76 @@
+--- configure.orig Fri Mar 25 01:48:07 2005
++++ configure Fri Mar 25 02:17:01 2005
+@@ -463,7 +463,7 @@
+ # include <unistd.h>
+ #endif"
+
+-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os GAMIN_MAJOR_VERSION GAMIN_MINOR_VERSION GAMIN_MICRO_VERSION GAMIN_VERSION GAMIN_VERSION_INFO FAM_VERSION_INFO INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL RELDATE HTML_DIR ENABLE_GTK_DOC_TRUE ENABLE_GTK_DOC_FALSE PKG_CONFIG DAEMON_CFLAGS DAEMON_LIBS LIBGAMIN_CFLAGS LIBGAMIN_LIBS TEST_CFLAGS TEST_LIBS GAMIN_DEBUG_TRUE GAMIN_DEBUG_FALSE BUILD_DOCS_TRUE BUILD_DOCS_FALSE HAVE_LINUX_TRUE HAVE_LINUX_FALSE ENABLE_DNOTIFY_TRUE ENABLE_DNOTIFY_FALSE ENABLE_INOTIFY_TRUE ENABLE_INOTIFY_FALSE PYTHON WITH_PYTHON_TRUE WITH_PYTHON_FALSE pythondir PYTHON_VERSION PYTHON_SUBDIR PYTHON_INCLUDES PYTHON_PYTHON_SITE_PACKAGES LIBOBJS LTLIBOBJS'
++ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os GAMIN_MAJOR_VERSION GAMIN_MINOR_VERSION GAMIN_MICRO_VERSION GAMIN_VERSION GAMIN_VERSION_INFO FAM_VERSION_INFO INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL RELDATE HTML_DIR ENABLE_GTK_DOC_TRUE ENABLE_GTK_DOC_FALSE PKG_CONFIG DAEMON_CFLAGS DAEMON_LIBS LIBGAMIN_CFLAGS LIBGAMIN_LIBS TEST_CFLAGS TEST_LIBS GAMIN_DEBUG_TRUE GAMIN_DEBUG_FALSE BUILD_DOCS_TRUE BUILD_DOCS_FALSE HAVE_LINUX_TRUE HAVE_LINUX_FALSE ENABLE_DNOTIFY_TRUE ENABLE_DNOTIFY_FALSE ENABLE_KQUEUE_TRUE ENABLE_KQUEUE_FALSE ENABLE_INOTIFY_TRUE ENABLE_INOTIFY_FALSE PYTHON WITH_PYTHON_TRUE WITH_PYTHON_FALSE pythondir PYTHON_VERSION PYTHON_SUBDIR PYTHON_INCLUDES PYTHON_SITE_PACKAGES LIBOBJS LTLIBOBJS'
+ ac_subst_files=''
+
+ # Initialize some variables set by options.
+@@ -21926,7 +21926,7 @@
+
+
+ debug_api=no
+-if test "`hostname`" == "paphio" -a "`pwd`" == "/u/veillard/gamin"
++if test "`hostname`" = "paphio" -a "`pwd`" = "/u/veillard/gamin"
+ then
+ debug_api=yes
+ fi
+@@ -22051,6 +22051,37 @@
+ backends="${backends}, dnotify"
+ fi
+
++if test "${enable_kqueue+set}" = set; then
++ enableval="$enable_kqueue"
++ case "${enableval}" in
++ yes) kqueue=true ;;
++ no) kqueue=false ;;
++ *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --disable-kqueue" >&5
++echo "$as_me: error: bad value ${enableval} for --disable-kqueue" >&2;}
++ { (exit 1); exit 1; }; } ;;
++ esac
++else
++ kqueue=true
++fi
++
++if test x$kqueue = xtrue; then
++ ENABLE_KQUEUE_TRUE=
++ ENABLE_KQUEUE_FALSE='#'
++else
++ ENABLE_KQUEUE_TRUE='#'
++ ENABLE_KQUEUE_FALSE=
++fi
++
++
++if test x$kqueue = xtrue; then
++
++cat >>confdefs.h <<\_ACEOF
++#define ENABLE_KQUEUE 1
++_ACEOF
++
++ backends="${backends}, kqueue"
++fi
++
+ if test x$os = xlinux-gnu; then
+ # Check whether --enable-inotify or --disable-inotify was given.
+ if test "${enable_inotify+set}" = set; then
+@@ -23472,6 +23503,8 @@
+ s,@HAVE_LINUX_FALSE@,$HAVE_LINUX_FALSE,;t t
+ s,@ENABLE_DNOTIFY_TRUE@,$ENABLE_DNOTIFY_TRUE,;t t
+ s,@ENABLE_DNOTIFY_FALSE@,$ENABLE_DNOTIFY_FALSE,;t t
++s,@ENABLE_KQUEUE_TRUE@,$ENABLE_KQUEUE_TRUE,;t t
++s,@ENABLE_KQUEUE_FALSE@,$ENABLE_KQUEUE_FALSE,;t t
+ s,@ENABLE_INOTIFY_TRUE@,$ENABLE_INOTIFY_TRUE,;t t
+ s,@ENABLE_INOTIFY_FALSE@,$ENABLE_INOTIFY_FALSE,;t t
+ s,@PYTHON@,$PYTHON,;t t
+@@ -23481,7 +23514,7 @@
+ s,@PYTHON_VERSION@,$PYTHON_VERSION,;t t
+ s,@PYTHON_SUBDIR@,$PYTHON_SUBDIR,;t t
+ s,@PYTHON_INCLUDES@,$PYTHON_INCLUDES,;t t
+-s,@PYTHON_PYTHON_SITE_PACKAGES@,$PYTHON_PYTHON_SITE_PACKAGES,;t t
++s,@PYTHON_SITE_PACKAGES@,$PYTHON_SITE_PACKAGES,;t t
+ s,@LIBOBJS@,$LIBOBJS,;t t
+ s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+ CEOF
diff --git a/devel/gamin/files/patch-configure.in b/devel/gamin/files/patch-configure.in
new file mode 100644
index 000000000000..b1e2cdebc85a
--- /dev/null
+++ b/devel/gamin/files/patch-configure.in
@@ -0,0 +1,31 @@
+--- configure.in.orig Wed Mar 30 15:19:06 2005
++++ configure.in Wed Mar 30 15:38:58 2005
+@@ -230,6 +230,28 @@
+ backends="${backends}, inotify"
+ fi
+
++if test x$os != xBogusOS; then
++ AC_CHECK_FUNC(kevent,[have_kevent=1],)
++ if test x$have_kevent = x1 ; then
++ AC_ARG_ENABLE(kqueue,
++ [ --disable-kqueue Disable the KQueue backend],
++ [case "${enableval}" in
++ yes) kqueue=true ;;
++ no) kqueue=false ;;
++ *) AC_MSG_ERROR(bad value ${enableval} for --disable-kqueue) ;;
++ esac],[kqueue=true])
++ fi
++fi
++
++dnl check if kqueue backend is enabled
++AM_CONDITIONAL(ENABLE_KQUEUE, test x$kqueue = xtrue)
++
++if test x$kqueue = xtrue; then
++ AC_CHECK_HEADERS(sys/event.h)
++ AC_DEFINE(ENABLE_KQUEUE,1,[Use kqueue as backend])
++ backends="${backends}, kqueue"
++fi
++
+ dnl check for flavours of varargs macros (test from GLib)
+ AC_MSG_CHECKING(for ISO C99 varargs macros in C)
+ AC_TRY_COMPILE([],[
diff --git a/devel/gamin/files/patch-libgamin_gam_api.c b/devel/gamin/files/patch-libgamin_gam_api.c
new file mode 100644
index 000000000000..c5cedfce6801
--- /dev/null
+++ b/devel/gamin/files/patch-libgamin_gam_api.c
@@ -0,0 +1,98 @@
+--- libgamin/gam_api.c.orig Thu Mar 24 19:07:08 2005
++++ libgamin/gam_api.c Thu Mar 24 19:26:39 2005
+@@ -181,7 +181,6 @@ gamin_get_socket_dir(void)
+ snprintf(path, MAXPATHLEN, "/tmp/fam-%s", user);
+ path[MAXPATHLEN] = 0;
+ ret = strdup(path);
+- free(user);
+ return (ret);
+ }
+
+@@ -421,9 +420,35 @@ gamin_write_credential_byte(int fd)
+ {
+ char data[2] = { 0, 0 };
+ int written;
++#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
++ struct {
++ struct cmsghdr hdr;
++ struct cmsgcred cred;
++ } cmsg;
++ struct iovec iov;
++ struct msghdr msg;
++
++ iov.iov_base = &data[0];
++ iov.iov_len = 1;
++
++ memset (&msg, 0, sizeof (msg));
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ msg.msg_control = &cmsg;
++ msg.msg_controllen = sizeof (cmsg);
++ memset (&cmsg, 0, sizeof (cmsg));
++ cmsg.hdr.cmsg_len = sizeof (cmsg);
++ cmsg.hdr.cmsg_level = SOL_SOCKET;
++ cmsg.hdr.cmsg_type = SCM_CREDS;
++#endif
+
+ retry:
++#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
++ written = sendmsg(fd, &msg, 0);
++#else
+ written = write(fd, &data[0], 1);
++#endif
+ if (written < 0) {
+ if (errno == EINTR)
+ goto retry;
+@@ -616,8 +641,10 @@ gamin_check_cred(GAMDataPtr conn, int fd
+ gid_t c_gid;
+
+ #ifdef HAVE_CMSGCRED
+- char cmsgmem[CMSG_SPACE(sizeof(struct cmsgcred))];
+- struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
++ struct {
++ struct cmsghdr hdr;
++ struct cmsgcred cred;
++ } cmsg;
+ #endif
+
+ s_uid = getuid();
+@@ -642,9 +669,9 @@ gamin_check_cred(GAMDataPtr conn, int fd
+ msg.msg_iovlen = 1;
+
+ #ifdef HAVE_CMSGCRED
+- memset(cmsgmem, 0, sizeof(cmsgmem));
+- msg.msg_control = cmsgmem;
+- msg.msg_controllen = sizeof(cmsgmem);
++ memset(&cmsg, 0, sizeof(cmsg));
++ msg.msg_control = &cmsg;
++ msg.msg_controllen = sizeof(cmsg);
+ #endif
+
+ retry:
+@@ -661,7 +688,7 @@ retry:
+ goto failed;
+ }
+ #ifdef HAVE_CMSGCRED
+- if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) {
++ if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
+ GAM_DEBUG(DEBUG_INFO,
+ "Message from recvmsg() was not SCM_CREDS\n");
+ goto failed;
+@@ -687,13 +714,9 @@ retry:
+ goto failed;
+ }
+ #elif defined(HAVE_CMSGCRED)
+- struct cmsgcred *cred;
+-
+- cred = (struct cmsgcred *) CMSG_DATA(cmsg);
+-
+- c_pid = cred->cmcred_pid;
+- c_uid = cred->cmcred_euid;
+- c_gid = cred->cmcred_groups[0];
++ c_pid = cmsg.cred.cmcred_pid;
++ c_uid = cmsg.cred.cmcred_euid;
++ c_gid = cmsg.cred.cmcred_groups[0];
+ #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+ GAM_DEBUG(DEBUG_INFO,
+ "Socket credentials not supported on this OS\n");
diff --git a/devel/gamin/files/patch-python_Makefile.in b/devel/gamin/files/patch-python_Makefile.in
new file mode 100644
index 000000000000..13580076c7f3
--- /dev/null
+++ b/devel/gamin/files/patch-python_Makefile.in
@@ -0,0 +1,32 @@
+--- python/Makefile.in.orig Thu Mar 24 19:56:18 2005
++++ python/Makefile.in Thu Mar 24 19:58:01 2005
+@@ -59,7 +59,7 @@
+ pythonLTLIBRARIES_INSTALL = $(INSTALL)
+ LTLIBRARIES = $(python_LTLIBRARIES)
+ @WITH_PYTHON_TRUE@am__DEPENDENCIES_1 = \
+-@WITH_PYTHON_TRUE@ $(top_builddir)/libgamin/libgamin-1.la
++@WITH_PYTHON_TRUE@ -lgamin-1
+ @WITH_PYTHON_TRUE@_gamin_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+ am___gamin_la_SOURCES_DIST = gamin.c
+ @WITH_PYTHON_TRUE@am__gamin_la_OBJECTS = gamin.lo
+@@ -162,7 +162,7 @@
+ PKG_CONFIG = @PKG_CONFIG@
+ PYTHON = @PYTHON@
+ PYTHON_INCLUDES = @PYTHON_INCLUDES@
+-PYTHON_PYTHON_SITE_PACKAGES = @PYTHON_PYTHON_SITE_PACKAGES@
++PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@
+ PYTHON_SUBDIR = @PYTHON_SUBDIR@
+ PYTHON_VERSION = @PYTHON_VERSION@
+ RANLIB = @RANLIB@
+@@ -233,9 +233,9 @@
+ gamin.c \
+ gamin.py
+
+-_gamin_la_LDFLAGS = -module -avoid-version -L$(top_builddir)/libgamin/.libs
++_gamin_la_LDFLAGS = -module -avoid-version
+ @WITH_PYTHON_TRUE@mylibs = \
+-@WITH_PYTHON_TRUE@ $(top_builddir)/libgamin/libgamin-1.la
++@WITH_PYTHON_TRUE@ -lgamin-1
+
+ @WITH_PYTHON_TRUE@python_LTLIBRARIES = _gamin.la
+ @WITH_PYTHON_TRUE@_gamin_la_SOURCES = gamin.c
diff --git a/devel/gamin/files/patch-server_Makefile.in b/devel/gamin/files/patch-server_Makefile.in
new file mode 100644
index 000000000000..233298647382
--- /dev/null
+++ b/devel/gamin/files/patch-server_Makefile.in
@@ -0,0 +1,47 @@
+--- server/Makefile.in.orig Thu Mar 24 23:04:39 2005
++++ server/Makefile.in Thu Mar 24 23:07:52 2005
+@@ -43,6 +43,7 @@
+ libexec_PROGRAMS = gam_server$(EXEEXT)
+ @ENABLE_INOTIFY_TRUE@am__append_2 = gam_inotify.c gam_inotify.h
+ @ENABLE_DNOTIFY_TRUE@am__append_3 = gam_dnotify.c gam_dnotify.h
++@ENABLE_KQUEUE_TRUE@am__append_4 = gam_kqueue.c gam_kqueue.h
+ subdir = server
+ DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+@@ -63,15 +64,16 @@
+ gam_connection.h gam_debugging.h gam_debugging.c \
+ gam_excludes.c gam_excludes.h local_inotify.h \
+ gam_debug_lists.c gam_inotify.c gam_inotify.h gam_dnotify.c \
+- gam_dnotify.h
++ gam_dnotify.h gam_kqueue.c gam_kqueue.h
+ @ENABLE_INOTIFY_TRUE@am__objects_1 = gam_inotify.$(OBJEXT)
+ @ENABLE_DNOTIFY_TRUE@am__objects_2 = gam_dnotify.$(OBJEXT)
++@ENABLE_KQUEUE_TRUE@am__objects_3 = gam_kqueue.$(OBJEXT)
+ am_gam_server_OBJECTS = gam_subscription.$(OBJEXT) \
+ gam_listener.$(OBJEXT) gam_server.$(OBJEXT) gam_node.$(OBJEXT) \
+ gam_tree.$(OBJEXT) gam_poll.$(OBJEXT) gam_channel.$(OBJEXT) \
+ gam_connection.$(OBJEXT) gam_debugging.$(OBJEXT) \
+ gam_excludes.$(OBJEXT) gam_debug_lists.$(OBJEXT) \
+- $(am__objects_1) $(am__objects_2)
++ $(am__objects_1) $(am__objects_2) $(am__objects_3)
+ gam_server_OBJECTS = $(am_gam_server_OBJECTS)
+ am__DEPENDENCIES_1 =
+ DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+@@ -236,7 +238,8 @@
+ gam_poll.h gam_channel.c gam_channel.h gam_connection.c \
+ gam_connection.h gam_debugging.h gam_debugging.c \
+ gam_excludes.c gam_excludes.h local_inotify.h \
+- gam_debug_lists.c $(am__append_2) $(am__append_3)
++ gam_debug_lists.c $(am__append_2) $(am__append_3) \
++ $(am__append_4)
+ gam_server_LDFLAGS =
+ gam_server_DEPENDENCIES = $(DEPS)
+ gam_server_LDADD = $(top_builddir)/lib/libgamin_shared.a $(LDADDS) $(LIBGAMIN_LIBS)
+@@ -316,6 +319,7 @@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gam_debug_lists.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gam_debugging.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gam_dnotify.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gam_kqueue.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gam_excludes.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gam_inotify.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gam_listener.Po@am__quote@
diff --git a/devel/gamin/files/patch-server_gam_channel.c b/devel/gamin/files/patch-server_gam_channel.c
new file mode 100644
index 000000000000..7e51df41fd9a
--- /dev/null
+++ b/devel/gamin/files/patch-server_gam_channel.c
@@ -0,0 +1,127 @@
+--- server/gam_channel.c.orig Fri Jan 28 10:54:42 2005
++++ server/gam_channel.c Sat Mar 26 16:15:55 2005
+@@ -24,11 +24,53 @@
+ * to check the server credentials early on.
+ */
+ static gboolean
+-gam_client_conn_send_cred(GIOChannel * source, int fd)
++gam_client_conn_send_cred(int fd)
+ {
+ char data[2] = { 0, 0 };
++ int written;
++#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
++ struct {
++ struct cmsghdr hdr;
++ struct cmsgcred cred;
++ } cmsg;
++ struct iovec iov;
++ struct msghdr msg;
++
++ iov.iov_base = &data[0];
++ iov.iov_len = 1;
++
++ memset (&msg, 0, sizeof (msg));
++ msg.msg_iov = &iov;
++ msg.msg_iovlen = 1;
++
++ msg.msg_control = &cmsg;
++ msg.msg_controllen = sizeof (cmsg);
++ memset (&cmsg, 0, sizeof (cmsg));
++ cmsg.hdr.cmsg_len = sizeof (cmsg);
++ cmsg.hdr.cmsg_level = SOL_SOCKET;
++ cmsg.hdr.cmsg_type = SCM_CREDS;
++#endif
+
+- return(gam_client_conn_write(source, fd, &data[0], 1));
++retry:
++#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
++ written = sendmsg(fd, &msg, 0);
++#else
++ written = write(fd, &data[0], 1);
++#endif
++ if (written < 0) {
++ if (errno == EINTR)
++ goto retry;
++ gam_error(DEBUG_INFO,
++ "Failed to write credential bytes to socket %d\n", fd);
++ return (-1);
++ }
++ if (written != 1) {
++ gam_error(DEBUG_INFO, "Wrote %d credential bytes to socket %d\n",
++ written, fd);
++ return (-1);
++ }
++ GAM_DEBUG(DEBUG_INFO, "Wrote credential bytes to socket %d\n", fd);
++ return (written);
+ }
+
+ /**
+@@ -49,8 +91,10 @@ gam_client_conn_check_cred(GIOChannel *
+ gid_t c_gid;
+
+ #ifdef HAVE_CMSGCRED
+- char cmsgmem[CMSG_SPACE(sizeof(struct cmsgcred))];
+- struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
++ struct {
++ struct cmsghdr hdr;
++ struct cmsgcred cred;
++ } cmsg;
+ #endif
+
+ s_uid = getuid();
+@@ -75,9 +119,9 @@ gam_client_conn_check_cred(GIOChannel *
+ msg.msg_iovlen = 1;
+
+ #ifdef HAVE_CMSGCRED
+- memset(cmsgmem, 0, sizeof(cmsgmem));
+- msg.msg_control = cmsgmem;
+- msg.msg_controllen = sizeof(cmsgmem);
++ memset(&cmsg, 0, sizeof(cmsg));
++ msg.msg_control = &cmsg;
++ msg.msg_controllen = sizeof(cmsg);
+ #endif
+
+ retry:
+@@ -94,7 +138,7 @@ gam_client_conn_check_cred(GIOChannel *
+ goto failed;
+ }
+ #ifdef HAVE_CMSGCRED
+- if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) {
++ if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
+ GAM_DEBUG(DEBUG_INFO,
+ "Message from recvmsg() was not SCM_CREDS\n");
+ goto failed;
+@@ -120,13 +164,9 @@ gam_client_conn_check_cred(GIOChannel *
+ goto failed;
+ }
+ #elif defined(HAVE_CMSGCRED)
+- struct cmsgcred *cred;
+-
+- cred = (struct cmsgcred *) CMSG_DATA(cmsg);
+-
+- c_pid = cred->cmcred_pid;
+- c_uid = cred->cmcred_euid;
+- c_gid = cred->cmcred_groups[0];
++ c_pid = cmsg.cred.cmcred_pid;
++ c_uid = cmsg.cred.cmcred_euid;
++ c_gid = cmsg.cred.cmcred_groups[0];
+ #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+ GAM_DEBUG(DEBUG_INFO,
+ "Socket credentials not supported on this OS\n");
+@@ -149,7 +189,7 @@ gam_client_conn_check_cred(GIOChannel *
+ goto failed;
+ }
+
+- if (!gam_client_conn_send_cred(source, fd)) {
++ if (!gam_client_conn_send_cred(fd)) {
+ GAM_DEBUG(DEBUG_INFO, "Failed to send credential byte to client\n");
+ goto failed;
+ }
+@@ -305,6 +345,7 @@ gam_get_socket_path(const char *session)
+ gam_client_id = g_getenv("GAM_CLIENT_ID");
+ if (gam_client_id == NULL) {
+ GAM_DEBUG(DEBUG_INFO, "Error getting GAM_CLIENT_ID\n");
++ gam_client_id = "";
+ }
+ } else {
+ gam_client_id = session;
diff --git a/devel/gamin/files/patch-server_gam_kqueue.c b/devel/gamin/files/patch-server_gam_kqueue.c
new file mode 100644
index 000000000000..3e5fe770e78d
--- /dev/null
+++ b/devel/gamin/files/patch-server_gam_kqueue.c
@@ -0,0 +1,639 @@
+--- server/gam_kqueue.c.orig Thu Mar 31 20:39:54 2005
++++ server/gam_kqueue.c Fri Apr 1 01:09:11 2005
+@@ -0,0 +1,636 @@
++/*
++ * Copyright (C) 2005 Joe Marcus Clarke <marcus@FreeBSD.org>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++
++#include <config.h>
++#include <sys/types.h>
++#include <sys/event.h>
++#include <sys/time.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <signal.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <string.h>
++#include <glib.h>
++#include "gam_error.h"
++#include "gam_kqueue.h"
++#include "gam_tree.h"
++#include "gam_event.h"
++#include "gam_server.h"
++#include "gam_event.h"
++
++typedef struct {
++ char *path;
++ int fd;
++ int refcount;
++ gboolean isdir;
++ GList *subs;
++ GSList *dirlist;
++} KQueueData;
++
++static GHashTable *dir_path_hash = NULL;
++static GHashTable *file_path_hash = NULL;
++static GHashTable *fd_hash = NULL;
++
++static GSList *exist_list = NULL;
++
++static GList *new_subs = NULL;
++G_LOCK_DEFINE_STATIC(new_subs);
++static GList *removed_subs = NULL;
++G_LOCK_DEFINE_STATIC(removed_subs);
++
++G_LOCK_DEFINE_STATIC(kqueue);
++
++static gboolean have_consume_idler = FALSE;
++
++int kq = -1;
++
++static KQueueData *
++gam_kqueue_data_new(const char *path, int fd)
++{
++ KQueueData *data;
++
++ data = g_new0(KQueueData, 1);
++ data->path = g_strdup(path);
++ data->fd = fd;
++ data->refcount = 1;
++ data->isdir = FALSE;
++ data->subs = NULL;
++ data->dirlist = NULL;
++
++ return data;
++}
++
++static GSList *
++gam_kqueue_lsdir(const char *path)
++{
++ GDir *dir;
++ GSList *lst = NULL;
++ const gchar *entry;
++
++ if (!path)
++ return NULL;
++
++ dir = g_dir_open(path, 0, NULL);
++ if (!dir)
++ return NULL;
++
++ entry = g_dir_read_name(dir);
++
++ while (entry) {
++ lst = g_slist_prepend(lst, g_strdup(entry));
++ entry = g_dir_read_name(dir);
++ }
++
++ g_dir_close(dir);
++
++ return lst;
++}
++
++static void
++gam_kqueue_cmplst(GSList *lst1, GSList *lst2, GSList **added, GSList **deleted)
++{
++ int found;
++ GSList *l;
++
++ if (!lst1 && !lst2)
++ return;
++
++ if (!lst1) {
++ *added = g_slist_copy(lst2);
++ return;
++ }
++
++ if (!lst2) {
++ *deleted = g_slist_copy(lst1);
++ return;
++ }
++
++ for (l = lst1; l; l = l->next) {
++ found = 0;
++ if (g_slist_find_custom(lst2, l->data, (GCompareFunc)strcmp)) {
++ found = 1;
++ }
++ if (found == 0) {
++ *deleted = g_slist_prepend(*deleted, l->data);
++ }
++ }
++
++ for (l = lst2; l; l = l->next) {
++ found = 0;
++ if (g_slist_find_custom(lst1, l->data, (GCompareFunc)strcmp)) {
++ found = 1;
++ }
++ if (found == 0) {
++ *added = g_slist_prepend(*added, l->data);
++ }
++ }
++}
++
++static void
++gam_kqueue_data_free(KQueueData * data)
++{
++ g_free(data->path);
++ if (data->dirlist) {
++ g_slist_foreach(data->dirlist, (GFunc)g_free, NULL);
++ g_slist_free(data->dirlist);
++ }
++ if (data->subs) {
++ g_list_free(data->subs);
++ }
++ g_free(data);
++}
++
++static void
++gam_kqueue_add_rm_handler(const char *path, GamSubscription *sub, gboolean added, gboolean was_missing)
++{
++ KQueueData *data;
++ struct kevent ev[1];
++ int isdir = 0;
++ int fd;
++
++ G_LOCK(kqueue);
++
++ isdir = g_file_test(path, G_FILE_TEST_IS_DIR);
++ if (gam_subscription_is_dir(sub)) {
++ data = g_hash_table_lookup(dir_path_hash, path);
++ }
++ else {
++ data = g_hash_table_lookup(file_path_hash, path);
++ }
++
++ if (added) {
++ GList *subs;
++
++ subs = NULL;
++ subs = g_list_append(subs, sub);
++
++ if (data != NULL) {
++ data->refcount++;
++ data->subs = g_list_prepend(data->subs, sub);
++ G_UNLOCK(kqueue);
++ GAM_DEBUG(DEBUG_INFO, "kqueue updated refcount\n");
++ if (!was_missing) {
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_EXISTS, subs, 1);
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_ENDEXISTS, subs, 1);
++ }
++ else {
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_CREATED, subs, 1);
++ }
++ return;
++ }
++
++ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
++ data = gam_kqueue_data_new(path, -1);
++ data->subs = g_list_prepend(data->subs, sub);
++ exist_list = g_slist_append(exist_list, data);
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_DELETED, subs, 1);
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_ENDEXISTS, subs, 1);
++ G_UNLOCK(kqueue);
++ return;
++ }
++
++ fd = open(path, O_RDONLY);
++
++ if (fd < 0) {
++ G_UNLOCK(kqueue);
++ return;
++ }
++
++ EV_SET(ev, fd, EVFILT_VNODE,
++ EV_ADD | EV_ENABLE | EV_CLEAR, VN_NOTE_ALL, 0, 0);
++ kevent(kq, ev, 1, NULL, 0, NULL);
++
++ data = gam_kqueue_data_new(path, fd);
++ data->subs = g_list_prepend(data->subs, sub);
++
++ if (!was_missing) {
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_EXISTS, subs, 1);
++ }
++ else {
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_CREATED, subs, 1);
++ }
++ if (gam_subscription_is_dir(sub) && isdir) {
++ GSList *l;
++
++ data->isdir = TRUE;
++ data->dirlist = gam_kqueue_lsdir(path);
++
++ for (l = data->dirlist; l; l = l->next) {
++ char *tmpentry;
++
++ tmpentry = g_build_filename(path, l->data, NULL);
++ if (!was_missing) {
++ gam_server_emit_event (tmpentry,
++ g_file_test(tmpentry, G_FILE_TEST_IS_DIR),
++ GAMIN_EVENT_EXISTS, subs, 1);
++ }
++ g_free(tmpentry);
++ }
++ }
++
++ if (!was_missing) {
++ gam_server_emit_event (path, isdir, GAMIN_EVENT_ENDEXISTS, subs, 1);
++ }
++
++ g_hash_table_insert(fd_hash, GINT_TO_POINTER(data->fd), data);
++ if (data->isdir) {
++ g_hash_table_insert(dir_path_hash, data->path, data);
++ }
++ else {
++ g_hash_table_insert(file_path_hash, data->path, data);
++ }
++
++ if (subs)
++ g_list_free(subs);
++
++ GAM_DEBUG(DEBUG_INFO, "added kqueue watch for %s\n", path);
++ } else {
++
++ if (!data) {
++ G_UNLOCK(kqueue);
++ return;
++ }
++
++ if (g_list_find (data->subs, sub)) {
++ data->subs = g_list_remove_all (data->subs, sub);
++ }
++ data->refcount--;
++ GAM_DEBUG(DEBUG_INFO, "kqueue decremeneted refcount for %s\n", path);
++
++ if (data->refcount == 0) {
++ GList *l;
++
++ close(data->fd);
++ l = data->subs;
++ for (l = l; l; l = l->next) {
++ GamSubscription *sub = l->data;
++ gam_kqueue_remove_subscription (sub);
++ }
++ GAM_DEBUG(DEBUG_INFO, "removed kqueue watch for %s\n", data->path);
++ if (data->isdir) {
++ g_hash_table_remove(dir_path_hash, data->path);
++ }
++ else {
++ g_hash_table_remove(file_path_hash, data->path);
++ }
++ g_hash_table_remove(fd_hash, GINT_TO_POINTER(data->fd));
++ gam_kqueue_data_free(data);
++ }
++ }
++ G_UNLOCK(kqueue);
++}
++
++static GaminEventType kqueue_event_to_gamin_event (int mask)
++{
++ if ((mask & VN_NOTE_CHANGED) != 0)
++ return GAMIN_EVENT_CHANGED;
++ else if ((mask & NOTE_DELETE) != 0)
++ return GAMIN_EVENT_DELETED;
++ else if ((mask & NOTE_REVOKE) != 0)
++ return GAMIN_EVENT_ENDEXISTS;
++ else if ((mask & NOTE_RENAME) != 0)
++ return GAMIN_EVENT_MOVED;
++ else
++ return GAMIN_EVENT_UNKNOWN;
++}
++
++static void gam_kqueue_emit_event (KQueueData *data, struct kevent *event)
++{
++ GaminEventType gevent;
++ int isdir = 0;
++ char *event_path;
++
++ if (!data||!event)
++ return;
++
++ gevent = kqueue_event_to_gamin_event (event->fflags);
++
++ if (gevent == GAMIN_EVENT_UNKNOWN) {
++ return;
++ }
++
++ isdir = g_file_test(data->path, G_FILE_TEST_IS_DIR);
++
++ if (gevent == GAMIN_EVENT_CHANGED && data->isdir) {
++ GSList *dirlist = NULL, *added = NULL, *deleted = NULL;
++ GSList *l;
++
++ dirlist = gam_kqueue_lsdir(data->path);
++ gam_kqueue_cmplst(data->dirlist, dirlist, &added, &deleted);
++ if (added || deleted) {
++ for (l = deleted; l; l = l->next) {
++ data->dirlist = g_slist_remove(data->dirlist, l->data);
++ event_path = g_build_filename(data->path, l->data, NULL);
++ g_free(l->data);
++ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_DELETED) , event_path);
++
++ gam_server_emit_event (event_path, isdir,
++ GAMIN_EVENT_DELETED, data->subs, 1);
++ g_free(event_path);
++ }
++
++ for (l = added; l; l = l->next) {
++ dirlist = g_slist_remove(dirlist, l->data);
++ data->dirlist = g_slist_prepend(data->dirlist,
++ g_strdup(l->data));
++ event_path = g_build_filename(data->path, l->data, NULL);
++ g_free(l->data);
++ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_CREATED) , event_path);
++
++ gam_server_emit_event (event_path, isdir,
++ GAMIN_EVENT_CREATED, data->subs, 1);
++ g_free(event_path);
++ }
++
++ if (added)
++ g_slist_free(added);
++ if (deleted)
++ g_slist_free(deleted);
++ }
++
++ if (dirlist) {
++ g_slist_foreach(dirlist, (GFunc)g_free, NULL);
++ g_slist_free(dirlist);
++ }
++ return;
++ }
++ else {
++ event_path = g_strdup (data->path);
++ }
++
++ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(gevent) , event_path);
++
++ gam_server_emit_event (event_path, isdir, gevent, data->subs, 1);
++
++ g_free (event_path);
++}
++
++static gboolean
++gam_kqueue_exist_check (gpointer user_data)
++{
++ GSList *l, *tmplst;
++ KQueueData *data;
++
++ tmplst = g_slist_copy(exist_list);
++
++ for (l = tmplst; l; l = l->next) {
++ data = l->data;
++
++ if (g_file_test(data->path, G_FILE_TEST_EXISTS)) {
++ /* The subs list is guaranteed to have only one entry. */
++ GamSubscription *sub = data->subs->data;
++
++ exist_list = g_slist_remove(exist_list, data);
++ gam_kqueue_add_rm_handler(data->path, sub, TRUE, TRUE);
++ gam_kqueue_data_free(data);
++ }
++ }
++
++ if (tmplst)
++ g_slist_free(tmplst);
++
++ return TRUE;
++}
++
++static gboolean
++gam_kqueue_event_handler (gpointer user_data)
++{
++ KQueueData *data;
++ struct kevent ev[1];
++ struct timespec timeout = { 0, 0 };
++ int fd, i, nevents;
++
++ G_LOCK(kqueue);
++
++ GAM_DEBUG(DEBUG_INFO, "gam_kqueue_event_handler()\n");
++
++ nevents = kevent(kq, NULL, 0, ev, 1, &timeout);
++ if (nevents == -1)
++ return FALSE;
++ for (i = 0; i < nevents; i++) {
++ fd = ev[i].ident;
++
++ data = g_hash_table_lookup (fd_hash, GINT_TO_POINTER(fd));
++ if (!data) {
++ GAM_DEBUG(DEBUG_INFO, "kqueue can't find fd %d\n", fd);
++ GAM_DEBUG(DEBUG_INFO, "weird things have happened to kqueue.\n");
++ } else {
++ gam_kqueue_emit_event (data, &ev[i]);
++ }
++
++ }
++
++ G_UNLOCK(kqueue);
++
++ return TRUE;
++}
++
++static gboolean
++gam_kqueue_consume_subscriptions_real(gpointer data)
++{
++ GList *subs, *l;
++
++ G_LOCK(new_subs);
++ if (new_subs) {
++ subs = new_subs;
++ new_subs = NULL;
++ G_UNLOCK(new_subs);
++
++ for (l = subs; l; l = l->next) {
++ GamSubscription *sub = l->data;
++ GAM_DEBUG(DEBUG_INFO, "called gam_kqueue_add_handler()\n");
++ gam_kqueue_add_rm_handler (gam_subscription_get_path (sub), sub, TRUE, FALSE);
++ }
++
++ } else {
++ G_UNLOCK(new_subs);
++ }
++
++ G_LOCK(removed_subs);
++ if (removed_subs) {
++ subs = removed_subs;
++ removed_subs = NULL;
++ G_UNLOCK(removed_subs);
++
++ for (l = subs; l; l = l->next) {
++ GamSubscription *sub = l->data;
++ GAM_DEBUG(DEBUG_INFO, "called gam_kqueue_rm_handler()\n");
++ gam_kqueue_add_rm_handler (gam_subscription_get_path (sub), sub, FALSE, FALSE);
++ }
++ } else {
++ G_UNLOCK(removed_subs);
++ }
++
++ GAM_DEBUG(DEBUG_INFO, "gam_kqueue_consume_subscriptions()\n");
++
++ have_consume_idler = FALSE;
++ return FALSE;
++}
++
++static void
++gam_kqueue_consume_subscriptions(void)
++{
++ GSource *source;
++
++ if (have_consume_idler)
++ return;
++
++ have_consume_idler = TRUE;
++
++ source = g_idle_source_new ();
++ g_source_set_callback (source, gam_kqueue_consume_subscriptions_real, NULL, NULL);
++
++ g_source_attach (source, NULL);
++}
++
++/**
++ * @defgroup kqueue kqueue backend
++ * @ingroup Backends
++ * @brief kqueue backend API
++ *
++ * Since 4.1, FreeBSD kernels have included the kernel event notification
++ * machanism (kqueue). This backend uses kqueue to know when
++ * files are changed/created/deleted.
++ *
++ * @{
++ */
++
++
++/**
++ * Initializes the kqueue system. This must be called before
++ * any other functions in this module.
++ *
++ * @returns TRUE if initialization succeeded, FALSE otherwise
++ */
++gboolean
++gam_kqueue_init(void)
++{
++ kq = kqueue();
++ if (kq == -1) {
++ GAM_DEBUG(DEBUG_INFO, "Could not initialize a new kqueue\n");
++ return FALSE;
++ }
++
++ g_timeout_add(1000, gam_kqueue_exist_check, NULL);
++ g_timeout_add(1000, gam_kqueue_event_handler, NULL);
++
++ dir_path_hash = g_hash_table_new(g_str_hash, g_str_equal);
++ file_path_hash = g_hash_table_new(g_str_hash, g_str_equal);
++ fd_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue initialized\n");
++
++ gam_backend_add_subscription = gam_kqueue_add_subscription;
++ gam_backend_remove_subscription = gam_kqueue_remove_subscription;
++ gam_backend_remove_all_for = gam_kqueue_remove_all_for;
++
++ return TRUE;
++}
++
++/**
++ * Adds a subscription to be monitored.
++ *
++ * @param sub a #GamSubscription to be polled
++ * @returns TRUE if adding the subscription succeeded, FALSE otherwise
++ */
++gboolean
++gam_kqueue_add_subscription(GamSubscription * sub)
++{
++ gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
++
++ G_LOCK(new_subs);
++ new_subs = g_list_prepend(new_subs, sub);
++ G_UNLOCK(new_subs);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue_add_sub\n");
++
++ gam_kqueue_consume_subscriptions();
++ return TRUE;
++}
++
++/**
++ * Removes a subscription which was being monitored.
++ *
++ * @param sub a #GamSubscription to remove
++ * @returns TRUE if removing the subscription succeeded, FALSE otherwise
++ */
++gboolean
++gam_kqueue_remove_subscription(GamSubscription * sub)
++{
++ G_LOCK(new_subs);
++ if (g_list_find(new_subs, sub)) {
++ GAM_DEBUG(DEBUG_INFO, "removed sub found on new_subs\n");
++ new_subs = g_list_remove_all (new_subs, sub);
++ G_UNLOCK(new_subs);
++ return TRUE;
++ }
++ G_UNLOCK(new_subs);
++
++ gam_subscription_cancel (sub);
++ gam_listener_remove_subscription(gam_subscription_get_listener(sub), sub);
++
++ G_LOCK(removed_subs);
++ removed_subs = g_list_prepend (removed_subs, sub);
++ G_UNLOCK(removed_subs);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue_remove_sub\n");
++ gam_kqueue_consume_subscriptions();
++
++ return TRUE;
++}
++
++/**
++ * Stop monitoring all subscriptions for a given listener.
++ *
++ * @param listener a #GamListener
++ * @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
++ */
++gboolean
++gam_kqueue_remove_all_for(GamListener * listener)
++{
++ GList *subs, *l = NULL;
++
++ subs = gam_listener_get_subscriptions (listener);
++
++ for (l = subs; l; l = l->next) {
++ GamSubscription *sub = l->data;
++
++ g_assert (sub != NULL);
++
++ gam_kqueue_remove_subscription (sub);
++
++ }
++
++ if (subs) {
++ g_list_free (subs);
++ gam_kqueue_consume_subscriptions();
++ return TRUE;
++ } else {
++ return FALSE;
++ }
++}
++
++/** @} */
diff --git a/devel/gamin/files/patch-server_gam_kqueue.h b/devel/gamin/files/patch-server_gam_kqueue.h
new file mode 100644
index 000000000000..c99f5e3ee380
--- /dev/null
+++ b/devel/gamin/files/patch-server_gam_kqueue.h
@@ -0,0 +1,27 @@
+--- server/gam_kqueue.h.orig Sat Mar 26 18:32:19 2005
++++ server/gam_kqueue.h Sat Mar 26 18:36:11 2005
+@@ -0,0 +1,24 @@
++
++#ifndef __MD_KQUEUE_H__
++#define __MD_KQUEUE_H__
++
++#include <glib.h>
++#include "gam_poll.h"
++#include "gam_subscription.h"
++
++#define VN_NOTE_MOST (NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | \
++ NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME | \
++ NOTE_REVOKE)
++#define VN_NOTE_ALL VN_NOTE_MOST
++#define VN_NOTE_CHANGED (NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK)
++
++G_BEGIN_DECLS
++
++gboolean gam_kqueue_init (void);
++gboolean gam_kqueue_add_subscription (GamSubscription *sub);
++gboolean gam_kqueue_remove_subscription (GamSubscription *sub);
++gboolean gam_kqueue_remove_all_for (GamListener *listener);
++
++G_END_DECLS
++
++#endif /* __MD_KQUEUE_H__ */
diff --git a/devel/gamin/files/patch-server_gam_server.c b/devel/gamin/files/patch-server_gam_server.c
new file mode 100644
index 000000000000..de62120f6ff6
--- /dev/null
+++ b/devel/gamin/files/patch-server_gam_server.c
@@ -0,0 +1,56 @@
+--- server/gam_server.c.orig Thu Dec 2 12:42:56 2004
++++ server/gam_server.c Sun Mar 27 02:34:19 2005
+@@ -39,12 +39,29 @@
+ #ifdef ENABLE_DNOTIFY
+ #include "gam_dnotify.h"
+ #endif
++#ifdef ENABLE_KQUEUE
++#include "gam_kqueue.h"
++#endif
+ #include "gam_excludes.h"
+
+ static int poll_only = 0;
+ static const char *session;
+
+ /**
++ * gam_exit:
++ *
++ * Call the shutdown routine, then just exit.
++ * This function is designed to be called from a
++ * signal handler.
++ */
++void
++gam_exit(int signo) {
++ gam_shutdown();
++
++ exit(0);
++}
++
++/**
+ * gam_shutdown:
+ *
+ * Shutdown routine called when the server exits
+@@ -90,6 +107,12 @@ gam_init_subscriptions(void)
+ return(TRUE);
+ }
+ #endif
++#ifdef ENABLE_KQUEUE
++ if (gam_kqueue_init()) {
++ GAM_DEBUG(DEBUG_INFO, "Using KQueue as backend\n");
++ return(TRUE);
++ }
++#endif
+ }
+ if (gam_poll_init()) {
+ GAM_DEBUG(DEBUG_INFO, "Using Poll as backend\n");
+@@ -332,6 +355,10 @@ main(int argc, const char *argv[])
+ }
+
+ gam_error_init();
++ signal(SIGHUP, gam_exit);
++ signal(SIGINT, gam_exit);
++ signal(SIGQUIT, gam_exit);
++ signal(SIGTERM, gam_exit);
+ signal(SIGPIPE, SIG_IGN);
+
+ if (!gam_init_subscriptions()) {
diff --git a/devel/gamin/pkg-descr b/devel/gamin/pkg-descr
new file mode 100644
index 000000000000..ac16e95d121f
--- /dev/null
+++ b/devel/gamin/pkg-descr
@@ -0,0 +1,5 @@
+Gamin is a file and directory monitoring system defined to be a subset of the
+FAM (File Alteration Monitor) system. This is a service provided by a library
+which allows to detect when a file or a directory has been modified.
+
+WWW: http://www.gnome.org/~veillard/gamin/index.html
diff --git a/devel/gamin/pkg-plist b/devel/gamin/pkg-plist
new file mode 100644
index 000000000000..d318e2257d82
--- /dev/null
+++ b/devel/gamin/pkg-plist
@@ -0,0 +1,10 @@
+include/fam.h
+lib/libfam.a
+lib/libfam.so
+lib/libfam.so.0
+lib/libgamin-1.a
+lib/libgamin-1.so
+lib/libgamin-1.so.0
+lib/libgamin_shared.a
+libdata/pkgconfig/gamin.pc
+libexec/gam_server