summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilles Dartiguelongue <eva@gentoo.org>2008-11-24 23:07:57 +0000
committerGilles Dartiguelongue <eva@gentoo.org>2008-11-24 23:07:57 +0000
commit630a7d65f5ec7b30d35cc57a99eae946f53515aa (patch)
tree1c629021c6530a406945e3d5ae3fb309925dee6c
parentStable on sparc, security bug #239130 and bug #241110 (diff)
downloadgentoo-2-630a7d65f5ec7b30d35cc57a99eae946f53515aa.tar.gz
gentoo-2-630a7d65f5ec7b30d35cc57a99eae946f53515aa.tar.bz2
gentoo-2-630a7d65f5ec7b30d35cc57a99eae946f53515aa.zip
New ebuild split off gamin. Initial ebuild inspired by Pacho Ramos, closes bug #217861.
(Portage version: 2.2_rc15/cvs/Linux 2.6.24-gentoo-r8-mactel x86_64)
-rw-r--r--dev-libs/libgamin/ChangeLog12
-rw-r--r--dev-libs/libgamin/files/gamin-0.1.9-freebsd.patch588
-rw-r--r--dev-libs/libgamin/files/libgamin-0.1.10-noinst-lib.patch76
-rw-r--r--dev-libs/libgamin/libgamin-0.1.10.ebuild76
-rw-r--r--dev-libs/libgamin/metadata.xml7
5 files changed, 759 insertions, 0 deletions
diff --git a/dev-libs/libgamin/ChangeLog b/dev-libs/libgamin/ChangeLog
new file mode 100644
index 000000000000..3a3813c488cf
--- /dev/null
+++ b/dev-libs/libgamin/ChangeLog
@@ -0,0 +1,12 @@
+# ChangeLog for dev-libs/libgamin
+# Copyright 1999-2008 Gentoo Foundation; Distributed under the GPL v2
+# $Header: /var/cvsroot/gentoo-x86/dev-libs/libgamin/ChangeLog,v 1.1 2008/11/24 23:07:56 eva Exp $
+
+*libgamin-0.1.10 (24 Nov 2008)
+
+ 24 Nov 2008; Gilles Dartiguelongue <eva@gentoo.org>
+ +files/gamin-0.1.9-freebsd.patch, +files/libgamin-0.1.10-noinst-lib.patch,
+ +libgamin-0.1.10.ebuild, +metadata.xml:
+ New ebuild split off gamin. Initial ebuild inspired by Pacho Ramos, closes
+ bug #217861.
+
diff --git a/dev-libs/libgamin/files/gamin-0.1.9-freebsd.patch b/dev-libs/libgamin/files/gamin-0.1.9-freebsd.patch
new file mode 100644
index 000000000000..3450f1bc5541
--- /dev/null
+++ b/dev-libs/libgamin/files/gamin-0.1.9-freebsd.patch
@@ -0,0 +1,588 @@
+diff -ur a/libgamin/gam_api.c b/libgamin/gam_api.c
+--- a/libgamin/gam_api.c 2007-07-04 14:36:48 +0100
++++ b/libgamin/gam_api.c 2007-08-07 17:34:38 +0100
+@@ -14,6 +14,7 @@
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <sys/uio.h>
++#include <string.h>
+ #include "fam.h"
+ #include "gam_protocol.h"
+ #include "gam_data.h"
+@@ -428,10 +429,10 @@
+ {
+ char data[2] = { 0, 0 };
+ int written;
+-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
+- struct {
++#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
++ union {
+ struct cmsghdr hdr;
+- struct cmsgcred cred;
++ char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
+ } cmsg;
+ struct iovec iov;
+ struct msghdr msg;
+@@ -443,16 +444,16 @@
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+- msg.msg_control = &cmsg;
+- msg.msg_controllen = sizeof (cmsg);
++ msg.msg_control = (caddr_t) &cmsg;
++ msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
+ memset (&cmsg, 0, sizeof (cmsg));
+- cmsg.hdr.cmsg_len = sizeof (cmsg);
++ cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
+ cmsg.hdr.cmsg_level = SOL_SOCKET;
+ cmsg.hdr.cmsg_type = SCM_CREDS;
+ #endif
+
+ retry:
+-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
++#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
+ written = sendmsg(fd, &msg, 0);
+ #else
+ written = write(fd, &data[0], 1);
+@@ -654,15 +655,16 @@
+ gid_t c_gid;
+
+ #ifdef HAVE_CMSGCRED
+- struct {
++ struct cmsgcred *cred;
++ union {
+ struct cmsghdr hdr;
+- struct cmsgcred cred;
++ char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
+ } cmsg;
+ #endif
+
+ s_uid = getuid();
+
+-#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
++#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED) && !defined(__FreeBSD__)
+ /* Set the socket to receive credentials on the next message */
+ {
+ int on = 1;
+@@ -683,8 +685,8 @@
+
+ #ifdef HAVE_CMSGCRED
+ memset(&cmsg, 0, sizeof(cmsg));
+- msg.msg_control = &cmsg;
+- msg.msg_controllen = sizeof(cmsg);
++ msg.msg_control = (caddr_t) &cmsg;
++ msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
+ #endif
+
+ retry:
+@@ -701,7 +703,7 @@
+ goto failed;
+ }
+ #ifdef HAVE_CMSGCRED
+- if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
++ if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred)) || cmsg.hdr.cmsg_type != SCM_CREDS) {
+ GAM_DEBUG(DEBUG_INFO,
+ "Message from recvmsg() was not SCM_CREDS\n");
+ goto failed;
+@@ -727,9 +729,10 @@
+ goto failed;
+ }
+ #elif defined(HAVE_CMSGCRED)
+- c_pid = cmsg.cred.cmcred_pid;
+- c_uid = cmsg.cred.cmcred_euid;
+- c_gid = cmsg.cred.cmcred_groups[0];
++ cred = (struct cmsgcred *) CMSG_DATA (&cmsg);
++ c_pid = cred->cmcred_pid;
++ c_uid = cred->cmcred_euid;
++ c_gid = cred->cmcred_groups[0];
+ #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+ GAM_DEBUG(DEBUG_INFO,
+ "Socket credentials not supported on this OS\n");
+@@ -1288,14 +1291,17 @@
+
+ // FIXME: drop and reacquire lock while blocked?
+ gamin_data_lock(conn);
+- if (!gamin_data_event_ready(conn)) {
++ while ((ret = gamin_data_event_ready(conn)) == 0) {
+ if (gamin_read_data(conn, fc->fd, 1) < 0) {
+ gamin_try_reconnect(conn, fc->fd);
+ FAMErrno = FAM_CONNECT;
+ return (-1);
+ }
+ }
+- ret = gamin_data_read_event(conn, fe);
++
++ if (ret > 0)
++ ret = gamin_data_read_event(conn, fe);
++
+ gamin_data_unlock(conn);
+
+ if (ret < 0) {
+diff -ur a/server/gam_channel.c b/server/gam_channel.c
+--- a/server/gam_channel.c 2007-07-04 14:36:49 +0100
++++ b/server/gam_channel.c 2007-08-07 17:34:38 +0100
+@@ -7,6 +7,7 @@
+ #include <sys/stat.h>
+ #include <sys/un.h>
+ #include <sys/uio.h>
++#include <string.h>
+ #include "gam_error.h"
+ #include "gam_connection.h"
+ #include "gam_channel.h"
+@@ -30,10 +31,10 @@
+ {
+ char data[2] = { 0, 0 };
+ int written;
+-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
+- struct {
++#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
++ union {
+ struct cmsghdr hdr;
+- struct cmsgcred cred;
++ char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
+ } cmsg;
+ struct iovec iov;
+ struct msghdr msg;
+@@ -45,16 +46,16 @@
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+- msg.msg_control = &cmsg;
+- msg.msg_controllen = sizeof (cmsg);
++ msg.msg_control = (caddr_t) &cmsg;
++ msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
+ memset (&cmsg, 0, sizeof (cmsg));
+- cmsg.hdr.cmsg_len = sizeof (cmsg);
++ cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
+ cmsg.hdr.cmsg_level = SOL_SOCKET;
+ cmsg.hdr.cmsg_type = SCM_CREDS;
+ #endif
+
+ retry:
+-#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
++#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
+ written = sendmsg(fd, &msg, 0);
+ #else
+ written = write(fd, &data[0], 1);
+@@ -95,15 +96,16 @@
+ gid_t c_gid;
+
+ #ifdef HAVE_CMSGCRED
+- struct {
++ struct cmsgcred *cred;
++ union {
+ struct cmsghdr hdr;
+- struct cmsgcred cred;
++ char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
+ } cmsg;
+ #endif
+
+ s_uid = getuid();
+
+-#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
++#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED) && !defined(__FreeBSD__)
+ /* Set the socket to receive credentials on the next message */
+ {
+ int on = 1;
+@@ -124,8 +126,8 @@
+
+ #ifdef HAVE_CMSGCRED
+ memset(&cmsg, 0, sizeof(cmsg));
+- msg.msg_control = &cmsg;
+- msg.msg_controllen = sizeof(cmsg);
++ msg.msg_control = (caddr_t) &cmsg;
++ msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
+ #endif
+
+ retry:
+@@ -142,7 +144,7 @@
+ goto failed;
+ }
+ #ifdef HAVE_CMSGCRED
+- if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
++ if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred)) || cmsg.hdr.cmsg_type != SCM_CREDS) {
+ GAM_DEBUG(DEBUG_INFO,
+ "Message from recvmsg() was not SCM_CREDS\n");
+ goto failed;
+@@ -168,9 +170,10 @@
+ goto failed;
+ }
+ #elif defined(HAVE_CMSGCRED)
+- c_pid = cmsg.cred.cmcred_pid;
+- c_uid = cmsg.cred.cmcred_euid;
+- c_gid = cmsg.cred.cmcred_groups[0];
++ cred = (struct cmsgcred *) CMSG_DATA (&cmsg);
++ c_pid = cred->cmcred_pid;
++ c_uid = cred->cmcred_euid;
++ c_gid = cred->cmcred_groups[0];
+ #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+ GAM_DEBUG(DEBUG_INFO,
+ "Socket credentials not supported on this OS\n");
+@@ -620,6 +623,7 @@
+ {
+ int fd;
+ struct sockaddr_un addr;
++ struct stat st;
+
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+@@ -640,9 +644,19 @@
+ * some extra protection checks. Also make sure the socket is created
+ * with restricted mode
+ */
+- if (!gam_check_secure_path(path)) {
++ if (!gam_check_secure_dir()) {
++ close(fd);
+ return (-1);
+ }
++
++ if (stat(path, &st) == 0) {
++ /* bind() will fail if the socket already exists */
++ if (unlink(path) < 0) {
++ GAM_DEBUG(DEBUG_INFO, "Failed to remove %s\n", path);
++ close(fd);
++ return (-1);
++ }
++ }
+ strncpy(&addr.sun_path[0], path, (sizeof(addr) - 4) - 1);
+ umask(0077);
+ #endif
+diff -ur a/server/gam_fs.c b/server/gam_fs.c
+--- a/server/gam_fs.c 2007-07-04 14:36:49 +0100
++++ b/server/gam_fs.c 2007-08-07 17:34:38 +0100
+@@ -7,6 +7,11 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <glib.h>
++#ifdef __FreeBSD__
++#include <sys/param.h>
++#include <sys/ucred.h>
++#include <sys/mount.h>
++#endif
+ #include "gam_error.h"
+ #include "gam_fs.h"
+
+@@ -21,9 +26,13 @@
+ typedef struct _gam_fs {
+ char *path;
+ char *fsname;
++ guint64 flags;
+ } gam_fs;
+
+ static gboolean initialized = FALSE;
++#ifdef __FreeBSD__
++static gboolean initializing = FALSE;
++#endif
+ static GList *filesystems = NULL;
+ static GList *fs_props = NULL;
+ static struct stat mtab_sbuf;
+@@ -110,6 +119,7 @@
+ return strlen(fsb->path) - strlen (fsa->path);
+ }
+
++#ifdef __linux__
+ static void
+ gam_fs_scan_mtab (void)
+ {
+@@ -165,10 +175,41 @@
+ gam_fs_free_filesystems ();
+ filesystems = g_list_sort (new_filesystems, gam_fs_filesystem_sort_cb);
+ }
++#endif
++
++#ifdef __FreeBSD__
++static void
++gam_fs_getmntinfo (void)
++{
++ struct statfs *stat;
++ GList *new_filesystems = NULL;
++ gam_fs *fs = NULL;
++ int i, n;
++
++ n = getmntinfo(&stat, MNT_NOWAIT);
++ if (n == -1)
++ return;
++
++ for (i = 0; i < n; i++)
++ {
++ fs = g_new0 (gam_fs, 1);
++ fs->path = g_strdup (stat[i].f_mntonname);
++ fs->fsname = g_strdup (stat[i].f_fstypename);
++ fs->flags = stat[i].f_flags;
++
++ new_filesystems = g_list_prepend (new_filesystems, fs);
++ }
++
++ /* Replace the old file systems list with the new one */
++ gam_fs_free_filesystems ();
++ filesystems = g_list_sort (new_filesystems, gam_fs_filesystem_sort_cb);
++}
++#endif
+
+ void
+ gam_fs_init (void)
+ {
++#if defined(__linux__)
+ if (initialized == FALSE)
+ {
+ initialized = TRUE;
+@@ -181,6 +222,7 @@
+ if (stat("/etc/mtab", &mtab_sbuf) != 0)
+ {
+ GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
++ return;
+ }
+ gam_fs_scan_mtab ();
+ } else {
+@@ -189,6 +231,7 @@
+ if (stat("/etc/mtab", &sbuf) != 0)
+ {
+ GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
++ return;
+ }
+
+ /* /etc/mtab has changed */
+@@ -199,6 +242,54 @@
+
+ mtab_sbuf = sbuf;
+ }
++#elif defined(__FreeBSD__)
++ if (initialized == FALSE && initializing == FALSE)
++ {
++ GList *iterator = NULL;
++ GHashTable *fs_hash = NULL;
++ gam_fs *fs = NULL;
++
++ initialized = TRUE;
++ initializing = TRUE;
++
++ gam_fs_getmntinfo ();
++
++ iterator = filesystems;
++ fs_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
++
++ while (iterator) {
++ fs = iterator->data;
++
++ if (!g_hash_table_lookup (fs_hash, fs->fsname)) {
++ if (fs->flags & MNT_LOCAL)
++ gam_fs_set (fs->fsname, GFS_MT_KERNEL, 0);
++ else
++ gam_fs_set (fs->fsname, GFS_MT_POLL, 5);
++
++ g_hash_table_insert (fs_hash, g_strdup (fs->fsname), GINT_TO_POINTER (1));
++ }
++
++ iterator = g_list_next (iterator);
++ }
++
++ g_hash_table_destroy (fs_hash);
++ initializing = FALSE;
++ } else if (initializing == FALSE) {
++ struct stat sbuf;
++
++ if (stat ("/etc/fstab", &sbuf) != 0) {
++ GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/fstab\n");
++ return;
++ }
++
++ if (sbuf.st_mtime != mtab_sbuf.st_mtime) {
++ GAM_DEBUG(DEBUG_INFO, "Updating list of mounted filesystems\n");
++ gam_fs_getmntinfo ();
++ }
++
++ mtab_sbuf = sbuf;
++ }
++#endif
+ }
+
+ gam_fs_mon_type
+@@ -209,10 +300,13 @@
+
+ props = gam_fs_find_fs_props (path);
+
+- if (!props)
+- return GFS_MT_DEFAULT;
+-
+- return props->mon_type;
++#if (defined(ENABLE_INOTIFY) || defined(ENABLE_DNOTIFY) || defined(ENABLE_KQUEUE) || defined(ENABLE_HURD_MACH_NOTIFY)) && defined(USE_GAMIN_POLLER)
++ if (props)
++ return props->mon_type;
++#elif !defined(USE_GAMIN_POLLER)
++ return GFS_MT_DEFAULT;
++#endif
++ return GFS_MT_POLL;
+ }
+
+ int
+diff -ur a/server/gam_kqueue.c b/server/gam_kqueue.c
+--- a/server/gam_kqueue.c 2007-07-04 14:50:41 +0100
++++ b/server/gam_kqueue.c 2007-08-07 17:34:38 +0100
+@@ -10,9 +10,10 @@
+ * FAM should do: we do not call g_dir_open() if the file is a
+ * symbolic link).
+ *
+- * * kqueue cannot monitor files residing on anything but a UFS
+- * file system. If kqueue cannot monitor a file, this backend
+- * will poll it periodically.
++ * * While kqueue is no longer tied to the UFS file system, it is
++ * better to not use it for remote file systems (because for
++ * such file systems, only local changes are detected by
++ * the kernel).
+ *
+ * * Monitoring a file with kqueue prevents the file system it
+ * resides on from being unmounted, because kqueue can only
+@@ -28,10 +29,9 @@
+ * - kqueue needs to be augmented with a filename-based
+ * monitoring facility;
+ *
+- * - kqueue needs to be moved out the UFS code.
+- *
+ * Copyright (C) 2005 Joe Marcus Clarke <marcus@FreeBSD.org>
+- * Copyright (C) 2005 Jean-Yves Lefort <jylefort@FreeBSD.org>
++ * Copyright (C) 2005, 2006 Jean-Yves Lefort <jylefort@FreeBSD.org>
++ * Copyright (C) 2006 Alex Dupre <ale@FreeBSD.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+@@ -53,6 +53,9 @@
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <sys/param.h>
++#ifndef USE_GAMIN_POLLER
++#include <sys/mount.h>
++#endif
+ #include <sys/types.h>
+ #include <sys/sysctl.h>
+ #include <sys/stat.h>
+@@ -509,6 +512,9 @@
+ gam_kqueue_monitor_enable_kqueue (Monitor *mon)
+ {
+ struct kevent ev[1];
++#ifndef USE_GAMIN_POLLER
++ struct statfs sb;
++#endif
+
+ if (open_files == max_open_files)
+ {
+@@ -516,26 +522,36 @@
+ return FALSE;
+ }
+
+- mon->fd = open(mon->pathname, O_RDONLY | O_NOFOLLOW);
++ mon->fd = open(mon->pathname, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
+ if (mon->fd < 0)
+ {
+ GAM_DEBUG(DEBUG_INFO, "cannot open %s (%s), falling back to poll\n", mon->pathname, g_strerror(errno));
+ return FALSE;
+ }
+
++#ifndef USE_GAMIN_POLLER
++ if (fstatfs(mon->fd, &sb) == 0 && (sb.f_flags & MNT_LOCAL) == 0)
++ {
++ GAM_DEBUG(DEBUG_INFO, "%s resides on a remote file system, falling back to poll\n", mon->pathname);
++ goto poll;
++ }
++#endif
++
+ EV_SET(ev, mon->fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, VN_NOTE_ALL, 0, mon);
+ if (kevent(kq, ev, G_N_ELEMENTS(ev), NULL, 0, NULL) < 0)
+ {
+ GAM_DEBUG(DEBUG_INFO, "cannot enable kqueue notification for %s (%s), falling back to poll\n", mon->pathname, g_strerror(errno));
+-
+- close(mon->fd);
+- mon->fd = -1;
+-
+- return FALSE;
++ goto poll;
+ }
+
+ open_files++;
+ return TRUE;
++
++ poll:
++ close(mon->fd);
++ mon->fd = -1;
++
++ return FALSE;
+ }
+
+ static void
+@@ -840,6 +856,8 @@
+ case GAMIN_EVENT_MOVED:
+ gam_kqueue_sub_monitor_set_missing(smon);
+ break;
++ default:
++ break;
+ }
+
+ gam_server_emit_event(mon->pathname, isdir, event, smon->subs, 1);
+@@ -981,6 +999,8 @@
+
+ gam_kqueue_hash_table_remove(fmon->smon->fmons, fmon);
+ break;
++ default:
++ break;
+ }
+ }
+
+diff -ur a/server/gam_node.c b/server/gam_node.c
+--- a/server/gam_node.c 2007-07-04 14:36:49 +0100
++++ b/server/gam_node.c 2007-08-07 17:34:38 +0100
+@@ -23,6 +23,7 @@
+ #include "gam_event.h"
+ #include "gam_node.h"
+ #include "gam_error.h"
++#include "gam_server.h"
+
+ /**
+ * Create a new node
+diff -ur a/server/gam_server.c b/server/gam_server.c
+--- a/server/gam_server.c 2007-07-04 14:36:49 +0100
++++ b/server/gam_server.c 2007-08-07 17:34:38 +0100
+@@ -32,7 +32,7 @@
+ #include "gam_server.h"
+ #include "gam_channel.h"
+ #include "gam_subscription.h"
+-#include "gam_poll_generic.h"
++#include "gam_poll_basic.h"
+ #ifdef ENABLE_INOTIFY
+ #include "gam_inotify.h"
+ #endif
+@@ -438,7 +438,7 @@
+ GamPollHandler
+ gam_server_get_poll_handler (void)
+ {
+- return __gam_kernel_handler;
++ return __gam_poll_handler;
+ }
+
+ gboolean
+diff -ur a/tests/testing.c b/tests/testing.c
+--- a/tests/testing.c 2007-07-04 14:36:49 +0100
++++ b/tests/testing.c 2007-08-07 17:34:38 +0100
+@@ -376,11 +376,11 @@
+ }
+ printf("chmod %s to %s\n", arg, arg2);
+ } else if (!strcmp(command, "chown")) {
++ struct stat sb;
+ if (args != 3) {
+ fprintf(stderr, "chown line %d: lacks path and owner\n", no);
+ return (-1);
+ }
+- struct stat sb;
+ if (!lstat (arg, &sb)) {
+ ret = (S_ISLNK (sb.st_mode)) ?
+ lchown(arg, strtol(arg2, NULL, 10), -1) :
+@@ -486,9 +486,9 @@
+ return (-1);
+ }
+ /*
+- * wait at most 3 secs before declaring failure
++ * wait at most 7 secs before declaring failure
+ */
+- while ((delay < 30) && (testState.nb_events < nb_events + count)) {
++ while ((delay < 70) && (testState.nb_events < nb_events + count)) {
+ debugLoop(100);
+
+ /* printf("+"); fflush(stdout); */
diff --git a/dev-libs/libgamin/files/libgamin-0.1.10-noinst-lib.patch b/dev-libs/libgamin/files/libgamin-0.1.10-noinst-lib.patch
new file mode 100644
index 000000000000..1f2fcff6f5b4
--- /dev/null
+++ b/dev-libs/libgamin/files/libgamin-0.1.10-noinst-lib.patch
@@ -0,0 +1,76 @@
+From e68aacc084d65fd0780991265444061b24422bd0 Mon Sep 17 00:00:00 2001
+From: Remi Cardona <remi@gentoo.org>
+Date: Mon, 20 Oct 2008 19:17:36 +0200
+Subject: [PATCH] make libgamin_shared a "noinst" libtool helper lib
+
+---
+ lib/Makefile.am | 4 ++--
+ libgamin/Makefile.am | 15 ++-------------
+ server/Makefile.am | 2 +-
+ 3 files changed, 5 insertions(+), 16 deletions(-)
+
+diff --git a/lib/Makefile.am b/lib/Makefile.am
+index 3e2289c..af2152a 100644
+--- a/lib/Makefile.am
++++ b/lib/Makefile.am
+@@ -7,9 +7,9 @@ if GAMIN_DEBUG
+ INCLUDES += -DGAM_DEBUG_ENABLED
+ endif
+
+-lib_LIBRARIES = libgamin_shared.a
++noinst_LTLIBRARIES = libgamin_shared.la
+
+-libgamin_shared_a_SOURCES = \
++libgamin_shared_la_SOURCES = \
+ gam_event.c \
+ gam_event.h \
+ gam_error.c \
+diff --git a/libgamin/Makefile.am b/libgamin/Makefile.am
+index 35aa740..14fc06b 100644
+--- a/libgamin/Makefile.am
++++ b/libgamin/Makefile.am
+@@ -25,19 +25,9 @@ libgamin_1_la_SOURCES = \
+ gam_data.h \
+ gam_fork.c \
+ gam_fork.h \
+- gam_protocol.h \
+- gam_error.c \
+- gam_event.c
++ gam_protocol.h
+
+-gam_error.c: $(top_srcdir)/lib/gam_error.c
+- @(cp $(top_srcdir)/lib/gam_error.c gam_error.c)
+-
+-gam_event.c: $(top_srcdir)/lib/gam_event.c
+- @(cp $(top_srcdir)/lib/gam_event.c gam_event.c)
+-
+-CLEANFILES=gam_error.c gam_event.c
+-
+-libgamin_1_la_LIBADD =
++libgamin_1_la_LIBADD = $(top_builddir)/lib/libgamin_shared.la
+
+ libgamin_1_la_LDFLAGS = -Wl,--version-script=$(srcdir)/gamin_sym.version \
+ -version-info @GAMIN_VERSION_INFO@ @THREAD_LIBS@
+@@ -54,6 +44,5 @@ noinst_PROGRAMS= gamin
+
+ gamin_SOURCES = gamin.c
+ gamin_LDFLAGS =
+-gamin_DEPENDENCIES = $(DEPS) libgamin-1.la
+ gamin_LDADD= $(LDADDS) libgamin-1.la
+
+diff --git a/server/Makefile.am b/server/Makefile.am
+index 37aed8b..6aa5e02 100644
+--- a/server/Makefile.am
++++ b/server/Makefile.am
+@@ -80,7 +80,7 @@ endif
+
+ gam_server_LDFLAGS =
+ gam_server_DEPENDENCIES = $(DEPS)
+-gam_server_LDADD= $(top_builddir)/lib/libgamin_shared.a $(LDADDS) $(DAEMON_LIBS)
++gam_server_LDADD= $(top_builddir)/lib/libgamin_shared.la $(LDADDS) $(DAEMON_LIBS)
+
+ if ENABLE_HURD_MACH_NOTIFY
+ gam_server_LDADD += -lports -lthreads
+--
+1.6.0.2
+
diff --git a/dev-libs/libgamin/libgamin-0.1.10.ebuild b/dev-libs/libgamin/libgamin-0.1.10.ebuild
new file mode 100644
index 000000000000..5704ef2f2c65
--- /dev/null
+++ b/dev-libs/libgamin/libgamin-0.1.10.ebuild
@@ -0,0 +1,76 @@
+# Copyright 1999-2008 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/dev-libs/libgamin/libgamin-0.1.10.ebuild,v 1.1 2008/11/24 23:07:56 eva Exp $
+
+inherit autotools eutils flag-o-matic libtool python
+
+MY_PN=${PN//lib/}
+MY_P=${MY_PN}-${PV}
+
+DESCRIPTION="Library providing the FAM File Alteration Monitor API"
+HOMEPAGE="http://www.gnome.org/~veillard/gamin/"
+SRC_URI="http://www.gnome.org/~veillard/${MY_PN}/sources/${MY_P}.tar.gz"
+
+LICENSE="LGPL-2"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~sparc-fbsd ~x86 ~x86-fbsd"
+IUSE="debug kernel_linux python"
+
+RESTRICT="test" # need gam-server
+
+RDEPEND="python? ( virtual/python )
+ !<app-admin/gamin-0.1.10"
+
+DEPEND="${RDEPEND}
+ dev-util/pkgconfig"
+
+S="${WORKDIR}/${MY_P}"
+
+src_unpack() {
+ unpack ${A}
+ cd "${S}"
+
+ # Fix compile warnings; bug #188923
+ epatch "${FILESDIR}/${MY_PN}-0.1.9-freebsd.patch"
+
+ # Fix collision problem due to intermediate library, upstream bug #530635
+ epatch "${FILESDIR}/${P}-noinst-lib.patch"
+
+ # autoconf is required as the user-cflags patch modifies configure.in
+ # however, elibtoolize is also required, so when the above patch is
+ # removed, replace the following call with a call to elibtoolize
+ eautoreconf
+}
+
+src_compile() {
+ # fixes bug #225403
+ #append-flags "-D_GNU_SOURCE"
+
+ econf --disable-debug \
+ --disable-server \
+ $(use_enable kernel_linux inotify) \
+ $(use_enable debug debug-api) \
+ $(use_with python)
+
+ emake || die "emake failed"
+}
+
+src_install() {
+ emake DESTDIR="${D}" install || die "installation failed"
+
+ dodoc AUTHORS ChangeLog README TODO NEWS doc/*txt
+ dohtml doc/*
+}
+
+pkg_postinst() {
+ if use python; then
+ python_version
+ python_mod_optimize /usr/$(get_libdir)/python${PYVER}/site-packages
+ fi
+}
+
+pkg_postrm() {
+ if use python; then
+ python_mod_cleanup /usr/$(get_libdir)/python*/site-packages
+ fi
+}
diff --git a/dev-libs/libgamin/metadata.xml b/dev-libs/libgamin/metadata.xml
new file mode 100644
index 000000000000..af7914839a81
--- /dev/null
+++ b/dev-libs/libgamin/metadata.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+<herd>gnome</herd>
+<herd>kde</herd>
+<herd>xfce</herd>
+</pkgmetadata>