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 #include #include +#include #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 #include #include +#include #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 #include #include +#ifdef __FreeBSD__ +#include +#include +#include +#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 - * Copyright (C) 2005 Jean-Yves Lefort + * Copyright (C) 2005, 2006 Jean-Yves Lefort + * Copyright (C) 2006 Alex Dupre * * 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 #include #include +#ifndef USE_GAMIN_POLLER +#include +#endif #include #include #include @@ -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); */