svn commit: samba r13848 - in trunk: examples/VFS source/include source/lib source/locking source/modules source/smbd

jra at samba.org jra at samba.org
Sun Mar 5 20:34:52 GMT 2006


Author: jra
Date: 2006-03-05 20:34:50 +0000 (Sun, 05 Mar 2006)
New Revision: 13848

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=13848

Log:
Rev the vfs to add the getlock call. We need this
for POSIX F_GETLK returns. Tidy up some of the
fcntl_lock code.
Jeremy.

Modified:
   trunk/examples/VFS/Makefile.in
   trunk/examples/VFS/skel_opaque.c
   trunk/examples/VFS/skel_transparent.c
   trunk/source/include/vfs.h
   trunk/source/include/vfs_macros.h
   trunk/source/lib/util.c
   trunk/source/locking/posix.c
   trunk/source/modules/vfs_full_audit.c
   trunk/source/smbd/vfs-wrap.c
   trunk/source/smbd/vfs.c


Changeset:
Modified: trunk/examples/VFS/Makefile.in
===================================================================
--- trunk/examples/VFS/Makefile.in	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/examples/VFS/Makefile.in	2006-03-05 20:34:50 UTC (rev 13848)
@@ -7,7 +7,7 @@
 SAMBA_SOURCE	= @SAMBA_SOURCE@
 SHLIBEXT	= @SHLIBEXT@
 OBJEXT		= @OBJEXT@ 
-FLAGS		=  $(CFLAGS) -Iinclude -I$(SAMBA_SOURCE)/include -I$(SAMBA_SOURCE)/popt -I$(SAMBA_SOURCE)/ubiqx -I$(SAMBA_SOURCE)/smbwrapper  -I. $(CPPFLAGS) -I$(SAMBA_SOURCE) -fPIC
+FLAGS		=  $(CFLAGS) -Iinclude -I$(SAMBA_SOURCE)/include -I$(SAMBA_SOURCE)/popt -I$(SAMBA_SOURCE)/smbwrapper  -I. $(CPPFLAGS) -I$(SAMBA_SOURCE) -fPIC
 
 
 prefix		= @prefix@

Modified: trunk/examples/VFS/skel_opaque.c
===================================================================
--- trunk/examples/VFS/skel_opaque.c	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/examples/VFS/skel_opaque.c	2006-03-05 20:34:50 UTC (rev 13848)
@@ -226,6 +226,11 @@
 	return vfswrap_lock(NULL, fsp, fd, op, offset, count, type);
 }
 
+static BOOL skel_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+	return vfswrap_getlock(NULL, fsp, fd, poffset, pcount, ptype, ppid);
+}
+
 static int skel_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath)
 {
 	return vfswrap_symlink(NULL, conn, oldpath, newpath);
@@ -576,6 +581,7 @@
 	{SMB_VFS_OP(skel_utime),			SMB_VFS_OP_UTIME,		SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(skel_ftruncate),			SMB_VFS_OP_FTRUNCATE,		SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(skel_lock),				SMB_VFS_OP_LOCK,		SMB_VFS_LAYER_OPAQUE},
+	{SMB_VFS_OP(skel_getlock),			SMB_VFS_OP_GETLOCK,		SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(skel_symlink),			SMB_VFS_OP_SYMLINK,		SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(skel_readlink),			SMB_VFS_OP_READLINK,		SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(skel_link),				SMB_VFS_OP_LINK,		SMB_VFS_LAYER_OPAQUE},

Modified: trunk/examples/VFS/skel_transparent.c
===================================================================
--- trunk/examples/VFS/skel_transparent.c	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/examples/VFS/skel_transparent.c	2006-03-05 20:34:50 UTC (rev 13848)
@@ -225,6 +225,11 @@
 	return SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type);
 }
 
+static BOOL skel_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+	return SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid);
+}
+
 static int skel_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath)
 {
 	return SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath);
@@ -543,6 +548,7 @@
 	{SMB_VFS_OP(skel_utime),			SMB_VFS_OP_UTIME,		SMB_VFS_LAYER_TRANSPARENT},
 	{SMB_VFS_OP(skel_ftruncate),			SMB_VFS_OP_FTRUNCATE,		SMB_VFS_LAYER_TRANSPARENT},
 	{SMB_VFS_OP(skel_lock),				SMB_VFS_OP_LOCK,		SMB_VFS_LAYER_TRANSPARENT},
+	{SMB_VFS_OP(skel_getlock),			SMB_VFS_OP_GETLOCK,		SMB_VFS_LAYER_TRANSPARENT},
 	{SMB_VFS_OP(skel_symlink),			SMB_VFS_OP_SYMLINK,		SMB_VFS_LAYER_TRANSPARENT},
 	{SMB_VFS_OP(skel_readlink),			SMB_VFS_OP_READLINK,		SMB_VFS_LAYER_TRANSPARENT},
 	{SMB_VFS_OP(skel_link),				SMB_VFS_OP_LINK,		SMB_VFS_LAYER_TRANSPARENT},

Modified: trunk/source/include/vfs.h
===================================================================
--- trunk/source/include/vfs.h	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/source/include/vfs.h	2006-03-05 20:34:50 UTC (rev 13848)
@@ -59,9 +59,10 @@
 /* Changed to version 12 to add mask and attributes to opendir(). JRA 
    Also include aio calls. JRA. */
 /* Changed to version 13 as the internal structure of files_struct has changed. JRA */
-/* Changed to version 14 as the we had to change DIR to SMB_STRUCT_DIR. JRA */
-/* Changed to version 15 as the we added the statvfs call. JRA */
-#define SMB_VFS_INTERFACE_VERSION 15
+/* Changed to version 14 as we had to change DIR to SMB_STRUCT_DIR. JRA */
+/* Changed to version 15 as we added the statvfs call. JRA */
+/* Changed to version 16 as we added the getlock call. JRA */
+#define SMB_VFS_INTERFACE_VERSION 16
 
 
 /* to bug old modules which are trying to compile with the old functions */
@@ -141,6 +142,7 @@
 	SMB_VFS_OP_UTIME,
 	SMB_VFS_OP_FTRUNCATE,
 	SMB_VFS_OP_LOCK,
+	SMB_VFS_OP_GETLOCK,
 	SMB_VFS_OP_SYMLINK,
 	SMB_VFS_OP_READLINK,
 	SMB_VFS_OP_LINK,
@@ -262,6 +264,7 @@
 		int (*utime)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, struct utimbuf *times);
 		int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_OFF_T offset);
 		BOOL (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+		BOOL (*getlock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
 		int (*symlink)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *oldpath, const char *newpath);
 		int (*readlink)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, char *buf, size_t bufsiz);
 		int (*link)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *oldpath, const char *newpath);
@@ -375,6 +378,7 @@
 		struct vfs_handle_struct *utime;
 		struct vfs_handle_struct *ftruncate;
 		struct vfs_handle_struct *lock;
+		struct vfs_handle_struct *getlock;
 		struct vfs_handle_struct *symlink;
 		struct vfs_handle_struct *readlink;
 		struct vfs_handle_struct *link;

Modified: trunk/source/include/vfs_macros.h
===================================================================
--- trunk/source/include/vfs_macros.h	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/source/include/vfs_macros.h	2006-03-05 20:34:50 UTC (rev 13848)
@@ -70,6 +70,7 @@
 #define SMB_VFS_UTIME(conn, path, times) ((conn)->vfs.ops.utime((conn)->vfs.handles.utime, (conn), (path), (times)))
 #define SMB_VFS_FTRUNCATE(fsp, fd, offset) ((fsp)->conn->vfs.ops.ftruncate((fsp)->conn->vfs.handles.ftruncate, (fsp), (fd), (offset)))
 #define SMB_VFS_LOCK(fsp, fd, op, offset, count, type) ((fsp)->conn->vfs.ops.lock((fsp)->conn->vfs.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
+#define SMB_VFS_GETLOCK(fsp, fd, poffset, pcount, ptype, ppid) ((fsp)->conn->vfs.ops.getlock((fsp)->conn->vfs.handles.getlock, (fsp), (fd) ,(poffset), (pcount), (ptype), (ppid)))
 #define SMB_VFS_SYMLINK(conn, oldpath, newpath) ((conn)->vfs.ops.symlink((conn)->vfs.handles.symlink, (conn), (oldpath), (newpath)))
 #define SMB_VFS_READLINK(conn, path, buf, bufsiz) ((conn)->vfs.ops.readlink((conn)->vfs.handles.readlink, (conn), (path), (buf), (bufsiz)))
 #define SMB_VFS_LINK(conn, oldpath, newpath) ((conn)->vfs.ops.link((conn)->vfs.handles.link, (conn), (oldpath), (newpath)))
@@ -181,6 +182,7 @@
 #define SMB_VFS_OPAQUE_UTIME(conn, path, times) ((conn)->vfs_opaque.ops.utime((conn)->vfs_opaque.handles.utime, (conn), (path), (times)))
 #define SMB_VFS_OPAQUE_FTRUNCATE(fsp, fd, offset) ((fsp)->conn->vfs_opaque.ops.ftruncate((fsp)->conn->vfs_opaque.handles.ftruncate, (fsp), (fd), (offset)))
 #define SMB_VFS_OPAQUE_LOCK(fsp, fd, op, offset, count, type) ((fsp)->conn->vfs_opaque.ops.lock((fsp)->conn->vfs_opaque.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
+#define SMB_VFS_OPAQUE_GETLOCK(fsp, fd, poffset, pcount, ptype, ppid) ((fsp)->conn->vfs_opaque.ops.getlock((fsp)->conn->vfs_opaque.handles.getlock, (fsp), (fd), (poffset), (pcount), (ptype), (ppid)))
 #define SMB_VFS_OPAQUE_SYMLINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.symlink((conn)->vfs_opaque.handles.symlink, (conn), (oldpath), (newpath)))
 #define SMB_VFS_OPAQUE_READLINK(conn, path, buf, bufsiz) ((conn)->vfs_opaque.ops.readlink((conn)->vfs_opaque.handles.readlink, (conn), (path), (buf), (bufsiz)))
 #define SMB_VFS_OPAQUE_LINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.link((conn)->vfs_opaque.handles.link, (conn), (oldpath), (newpath)))
@@ -293,6 +295,7 @@
 #define SMB_VFS_NEXT_UTIME(handle, conn, path, times) ((handle)->vfs_next.ops.utime((handle)->vfs_next.handles.utime, (conn), (path), (times)))
 #define SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset) ((handle)->vfs_next.ops.ftruncate((handle)->vfs_next.handles.ftruncate, (fsp), (fd), (offset)))
 #define SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type) ((handle)->vfs_next.ops.lock((handle)->vfs_next.handles.lock, (fsp), (fd) ,(op), (offset), (count), (type)))
+#define SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid) ((handle)->vfs_next.ops.getlock((handle)->vfs_next.handles.getlock, (fsp), (fd), (poffset), (pcount), (ptype), (ppid)))
 #define SMB_VFS_NEXT_SYMLINK(handle, conn, oldpath, newpath) ((handle)->vfs_next.ops.symlink((handle)->vfs_next.handles.symlink, (conn), (oldpath), (newpath)))
 #define SMB_VFS_NEXT_READLINK(handle, conn, path, buf, bufsiz) ((handle)->vfs_next.ops.readlink((handle)->vfs_next.handles.readlink, (conn), (path), (buf), (bufsiz)))
 #define SMB_VFS_NEXT_LINK(handle, conn, oldpath, newpath) ((handle)->vfs_next.ops.link((handle)->vfs_next.handles.link, (conn), (oldpath), (newpath)))

Modified: trunk/source/lib/util.c
===================================================================
--- trunk/source/lib/util.c	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/source/lib/util.c	2006-03-05 20:34:50 UTC (rev 13848)
@@ -1810,6 +1810,7 @@
 /****************************************************************************
  Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
  is dealt with in posix.c
+ Returns True if the lock was granted, False otherwise.
 ****************************************************************************/
 
 BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
@@ -1827,36 +1828,56 @@
 
 	ret = sys_fcntl_ptr(fd,op,&lock);
 
-	if (ret == -1 && errno != 0)
-		DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
-
-	/* a lock query */
-	if (op == SMB_F_GETLK) {
-		if ((ret != -1) &&
-				(lock.l_type != F_UNLCK) && 
-				(lock.l_pid != 0) && 
-				(lock.l_pid != sys_getpid())) {
-			DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
-			return(True);
-		}
-
-		/* it must be not locked or locked by me */
-		return(False);
-	}
-
-	/* a lock set or unset */
 	if (ret == -1) {
 		DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
 			(double)offset,(double)count,op,type,strerror(errno)));
-		return(False);
+		return False;
 	}
 
 	/* everything went OK */
 	DEBUG(8,("fcntl_lock: Lock call successful\n"));
 
-	return(True);
+	return True;
 }
 
+/****************************************************************************
+ Simple routine to query existing file locks. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
+ Returns True if we have information regarding this lock region (and returns
+ F_UNLCK in *ptype if the region is unlocked). False if the call failed.
+****************************************************************************/
+
+BOOL fcntl_getlock(int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+	SMB_STRUCT_FLOCK lock;
+	int ret;
+
+	DEBUG(8,("fcntl_getlock %d %.0f %.0f %d\n",fd,(double)*poffset,(double)*pcount,*ptype));
+
+	lock.l_type = *ptype;
+	lock.l_whence = SEEK_SET;
+	lock.l_start = *poffset;
+	lock.l_len = *pcount;
+	lock.l_pid = 0;
+
+	ret = sys_fcntl_ptr(fd,SMB_F_GETLK,&lock);
+
+	if (ret == -1) {
+		DEBUG(3,("fcntl_getlock: lock request failed at offset %.0f count %.0f type %d (%s)\n",
+			(double)*poffset,(double)*pcount,*ptype,strerror(errno)));
+		return False;
+	}
+
+	*ptype = lock.l_type;
+	*poffset = lock.l_start;
+	*pcount = lock.l_len;
+	*ppid = lock.l_pid;
+	
+	DEBUG(3,("fcntl_getlock: fd %d is returned info %d pid %u\n",
+			fd, (int)lock.l_type, (unsigned int)lock.l_pid));
+	return True;
+}
+
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_ALL
 

Modified: trunk/source/locking/posix.c
===================================================================
--- trunk/source/locking/posix.c	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/source/locking/posix.c	2006-03-05 20:34:50 UTC (rev 13848)
@@ -658,7 +658,12 @@
 
 	DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fh->fd,op,(double)offset,(double)count,type));
 
-	ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
+	if (op != SMB_F_GETLK) {
+		ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
+	} else {
+		pid_t pid;
+		ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,&offset,&count,&type,&pid);
+	}
 
 	if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno ==  EINVAL))) {
 
@@ -682,12 +687,16 @@
 			DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
 			errno = 0;
 			count &= 0x7fffffff;
-			ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
+			if (op != SMB_F_GETLK) {
+				ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
+			} else {
+				pid_t pid;
+				ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,&offset,&count,&type,&pid);
+			}
 		}
 	}
 
 	DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
-
 	return ret;
 }
 
@@ -723,7 +732,11 @@
 	 * fd. So we don't need to use map_lock_type here.
 	 */ 
 
-	return posix_fcntl_lock(fsp,SMB_F_GETLK,offset,count,posix_lock_type);
+	if (!posix_fcntl_lock(fsp,SMB_F_GETLK,&offset,&count,&posix_lock_type)) {
+		return False;
+	}
+
+	return (posix_lock_type != F_UNLCK ? True : False);
 }
 
 /*

Modified: trunk/source/modules/vfs_full_audit.c
===================================================================
--- trunk/source/modules/vfs_full_audit.c	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/source/modules/vfs_full_audit.c	2006-03-05 20:34:50 UTC (rev 13848)
@@ -161,6 +161,8 @@
 			   int fd, SMB_OFF_T len);
 static BOOL smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int fd,
 		       int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+static BOOL smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+		       SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
 static int smb_full_audit_symlink(vfs_handle_struct *handle, connection_struct *conn,
 			 const char *oldpath, const char *newpath);
 static int smb_full_audit_readlink(vfs_handle_struct *handle, connection_struct *conn,
@@ -399,6 +401,8 @@
 	 SMB_VFS_LAYER_LOGGER},
 	{SMB_VFS_OP(smb_full_audit_lock),	SMB_VFS_OP_LOCK,
 	 SMB_VFS_LAYER_LOGGER},
+	{SMB_VFS_OP(smb_full_audit_getlock),	SMB_VFS_OP_GETLOCK,
+	 SMB_VFS_LAYER_LOGGER},
 	{SMB_VFS_OP(smb_full_audit_symlink),	SMB_VFS_OP_SYMLINK,
 	 SMB_VFS_LAYER_LOGGER},
 	{SMB_VFS_OP(smb_full_audit_readlink),	SMB_VFS_OP_READLINK,
@@ -564,6 +568,7 @@
 	{ SMB_VFS_OP_UTIME,	"utime" },
 	{ SMB_VFS_OP_FTRUNCATE,	"ftruncate" },
 	{ SMB_VFS_OP_LOCK,	"lock" },
+	{ SMB_VFS_OP_GETLOCK,	"getlock" },
 	{ SMB_VFS_OP_SYMLINK,	"symlink" },
 	{ SMB_VFS_OP_READLINK,	"readlink" },
 	{ SMB_VFS_OP_LINK,	"link" },
@@ -1309,6 +1314,18 @@
 	return result;
 }
 
+static BOOL smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+		       SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+	BOOL result;
+
+	result = SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid);
+
+	do_log(SMB_VFS_OP_GETLOCK, (result >= 0), handle, "%s", fsp->fsp_name);
+
+	return result;
+}
+
 static int smb_full_audit_symlink(vfs_handle_struct *handle, connection_struct *conn,
 			 const char *oldpath, const char *newpath)
 {

Modified: trunk/source/smbd/vfs-wrap.c
===================================================================
--- trunk/source/smbd/vfs-wrap.c	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/source/smbd/vfs-wrap.c	2006-03-05 20:34:50 UTC (rev 13848)
@@ -759,11 +759,21 @@
 	BOOL result;
 
 	START_PROFILE(syscall_fcntl_lock);
-	result =  fcntl_lock(fd, op, offset, count,type);
+	result =  fcntl_lock(fd, op, offset, count, type);
 	END_PROFILE(syscall_fcntl_lock);
 	return result;
 }
 
+BOOL vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+{
+	BOOL result;
+
+	START_PROFILE(syscall_fcntl_getlock);
+	result =  fcntl_getlock(fd, poffset, pcount, ptype, ppid);
+	END_PROFILE(syscall_fcntl_getlock);
+	return result;
+}
+
 int vfswrap_symlink(vfs_handle_struct *handle, connection_struct *conn, const char *oldpath, const char *newpath)
 {
 	int result;

Modified: trunk/source/smbd/vfs.c
===================================================================
--- trunk/source/smbd/vfs.c	2006-03-05 18:28:33 UTC (rev 13847)
+++ trunk/source/smbd/vfs.c	2006-03-05 20:34:50 UTC (rev 13848)
@@ -95,6 +95,7 @@
 		vfswrap_utime,
 		vfswrap_ftruncate,
 		vfswrap_lock,
+		vfswrap_getlock,
 		vfswrap_symlink,
 		vfswrap_readlink,
 		vfswrap_link,



More information about the samba-cvs mailing list