[SCM] Samba Shared Repository - branch master updated

Martin Schwenke martins at samba.org
Tue Jul 23 12:40:02 UTC 2024


The branch, master has been updated
       via  ead5a3111f3 ctdb-daemon: Use ctdb_parse_node_address() in ctdbd
       via  181cc097ef2 ctdb-daemon: Use ctdb_read_nodes() in ctdbd
       via  5d2a864c0ba ctdb-protocol: Move ctdb_node_map_* to protocol_api.h
       via  fe97d04f180 ctdb-tests: Use ctdb_read_nodes() in the fake ctdbd
       via  3d52258d8ad ctdb-tools: Use ctdb_read_nodes() in the ctdb tool
       via  45da2281aa4 ctdb-conf: Add a common node address handling module
       via  79c5f451c86 ctdb-protocol: Move definition of CTDB_PORT to protocol
       via  67e49d3e541 ctdb-build: Remove unused dependencies on ctdb-util
      from  0a532378322 s3:printing: Allow to run samba-bgqd as a standalone systemd service

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit ead5a3111f3b3e0639b1dc7725a7c233f1ee9cae
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Mon Jul 8 17:57:27 2024 +1000

    ctdb-daemon: Use ctdb_parse_node_address() in ctdbd
    
    While here, fix a trivial memory leak (ctdbd will exit anyway if this
    function fails).
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>
    
    Autobuild-User(master): Martin Schwenke <martins at samba.org>
    Autobuild-Date(master): Tue Jul 23 12:39:18 UTC 2024 on atb-devel-224

commit 181cc097ef2d36d5aaeffa3636ea4f198306bb78
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Fri Jul 5 18:07:36 2024 +1000

    ctdb-daemon: Use ctdb_read_nodes() in ctdbd
    
    ctdb_control_getnodesfile() calls ctdb_read_nodes(), which returns a
    struct ctdb_node_map rather than the old version, so update associated
    marshalling.  While here modernise a debug message and wrap the
    function arguments.
    
    For ctdb_load_nodes_file() to use ctdb_read_nodes(), tweak
    convert_node_map_to_list() to also use the modern node map structure.
    
    Remove unused copy of ctdb_read_nodes_file().
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>

commit 5d2a864c0ba3e7a67a73548e2d13ea5919aa5fc7
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Fri Jul 5 17:58:46 2024 +1000

    ctdb-protocol: Move ctdb_node_map_* to protocol_api.h
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>

commit fe97d04f18084c6ac76106fce28e55db4b72b8cc
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Fri Jul 5 17:45:44 2024 +1000

    ctdb-tests: Use ctdb_read_nodes() in the fake ctdbd
    
    Remove unused copy of ctdb_read_nodes_file().
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>

commit 3d52258d8ad5dcef3f6d8b95bc289a6c11121a9c
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Fri Jul 5 17:37:26 2024 +1000

    ctdb-tools: Use ctdb_read_nodes() in the ctdb tool
    
    Remove unused copy of ctdb_read_nodes_file().
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>

commit 45da2281aa4f391e23883d1f8453991caa3d1dff
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Fri Jul 5 17:34:09 2024 +1000

    ctdb-conf: Add a common node address handling module
    
    These functions are intended to be used in ctdbd, the ctdb tool and
    fake_ctdbd, replacing the different copies in each place.
    
    ctdb_read_nodes() will replace ctdb_read_nodes_file().  The name
    change is intentional - in future the location may be something other
    than a simple filename.
    
    The static copies of ctdb_read_nodes_file() and node_map_add() are
    slightly sanitised versions of those in tools/ctdb.c, with a call to
    ctdb_parse_node_address().  A bit more care is taken in node_map_add()
    to avoid undefined behaviour if talloc_realloc() fails.
    
    ctdb_parse_node_address() will replace ctdb_parse_address().  There is
    an obvious argument change, since the ctdb context argument was
    unused.  It can only fail on an invalid node address, so return a
    bool.  This function might be changed later to allow the input address
    string to include an optional port.
    
    Where to put this module isn't entirely clear.  It could go in common,
    so be part of ctdb-util.  However, if it later needs
    ctdb-conf (e.g. to allow the node list location to be configurable)
    then there would be a direct cyclic dependency.  This is configuration
    handling, so conf/ seems sane.  However, I didn't want to put it into
    the ctdb-conf target, since some code might need to parse a nodes list
    but not need to parse ctdb.conf.
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>

commit 79c5f451c86fc5e5dd77d631ebbb394070055ba1
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Mon Jul 8 17:58:55 2024 +1000

    ctdb-protocol: Move definition of CTDB_PORT to protocol
    
    Users of CTDB_PORT will all pick up the new definition.
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>

commit 67e49d3e541f17d5174e5562e260ca57cd6d88be
Author: Martin Schwenke <mschwenke at ddn.com>
Date:   Fri Jul 5 17:19:47 2024 +1000

    ctdb-build: Remove unused dependencies on ctdb-util
    
    Since commit ba8f8ef33cd99ea60fc2682727a5497995b5f569.
    
    Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
    Reviewed-by: Anoop C S <anoopcs at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 ctdb/common/common.h             |   6 --
 ctdb/common/ctdb_util.c          | 134 ---------------------------
 ctdb/conf/node.c                 | 194 +++++++++++++++++++++++++++++++++++++++
 ctdb/conf/node.h                 |  54 +++++++++++
 ctdb/include/ctdb_protocol.h     |   3 -
 ctdb/protocol/protocol.h         |   2 +
 ctdb/protocol/protocol_api.h     |   5 +
 ctdb/protocol/protocol_private.h |   5 -
 ctdb/server/ctdb_daemon.c        |  40 ++++++--
 ctdb/server/ctdb_server.c        |  20 ++--
 ctdb/tests/src/fake_ctdbd.c      | 109 +---------------------
 ctdb/tools/ctdb.c                | 103 +--------------------
 ctdb/wscript                     |  56 +++++++++--
 13 files changed, 354 insertions(+), 377 deletions(-)
 create mode 100644 ctdb/conf/node.c
 create mode 100644 ctdb/conf/node.h


Changeset truncated at 500 lines:

diff --git a/ctdb/common/common.h b/ctdb/common/common.h
index 4f48e8926da..1f6f937663c 100644
--- a/ctdb/common/common.h
+++ b/ctdb/common/common.h
@@ -101,9 +101,6 @@ bool ctdb_set_helper(const char *type, char *helper, size_t size,
 		     const char *envvar,
 		     const char *dir, const char *file);
 
-int ctdb_parse_address(TALLOC_CTX *mem_ctx, const char *str,
-		       ctdb_sock_addr *address);
-
 bool ctdb_same_address(ctdb_sock_addr *a1, ctdb_sock_addr *a2);
 
 uint32_t ctdb_hash(const TDB_DATA *key);
@@ -142,9 +139,6 @@ char *ctdb_addr_to_str(ctdb_sock_addr *addr);
 
 unsigned ctdb_addr_to_port(ctdb_sock_addr *addr);
 
-struct ctdb_node_map_old *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
-					       const char *nlist);
-
 struct ctdb_node_map_old *ctdb_node_list_to_map(struct ctdb_node **nodes,
 						uint32_t num_nodes,
 						TALLOC_CTX *mem_ctx);
diff --git a/ctdb/common/ctdb_util.c b/ctdb/common/ctdb_util.c
index ebf0203871f..0b4876725a0 100644
--- a/ctdb/common/ctdb_util.c
+++ b/ctdb/common/ctdb_util.c
@@ -140,36 +140,6 @@ bool ctdb_set_helper(const char *type, char *helper, size_t size,
 	return true;
 }
 
-/*
-  parse a IP:port pair
-*/
-int ctdb_parse_address(TALLOC_CTX *mem_ctx, const char *str,
-		       ctdb_sock_addr *address)
-{
-	struct servent *se;
-	int port;
-	int ret;
-
-	setservent(0);
-	se = getservbyname("ctdb", "tcp");
-	endservent();
-
-	if (se == NULL) {
-		port = CTDB_PORT;
-	} else {
-		port = ntohs(se->s_port);
-	}
-
-	ret = ctdb_sock_addr_from_string(str, address, false);
-	if (ret != 0) {
-		return -1;
-	}
-	ctdb_sock_addr_set_port(address, port);
-
-	return 0;
-}
-
-
 /*
   check if two addresses are the same
 */
@@ -464,110 +434,6 @@ unsigned ctdb_addr_to_port(ctdb_sock_addr *addr)
 	return 0;
 }
 
-/* Add a node to a node map with given address and flags */
-static bool node_map_add(TALLOC_CTX *mem_ctx,
-			 const char *nstr, uint32_t flags,
-			 struct ctdb_node_map_old **node_map)
-{
-	ctdb_sock_addr addr;
-	uint32_t num;
-	size_t s;
-	struct ctdb_node_and_flags *n;
-
-	/* Might as well do this before trying to allocate memory */
-	if (ctdb_parse_address(mem_ctx, nstr, &addr) == -1) {
-		return false;
-	}
-
-	num = (*node_map)->num + 1;
-	s = offsetof(struct ctdb_node_map_old, nodes) +
-		num * sizeof(struct ctdb_node_and_flags);
-	*node_map = talloc_realloc_size(mem_ctx, *node_map, s);
-	if (*node_map == NULL) {
-		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
-		return false;
-	}
-
-	n = &(*node_map)->nodes[(*node_map)->num];
-	n->addr = addr;
-	n->pnn = (*node_map)->num;
-	n->flags = flags;
-
-	(*node_map)->num++;
-
-	return true;
-}
-
-/* Read a nodes file into a node map */
-struct ctdb_node_map_old *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
-					   const char *nlist)
-{
-	char **lines;
-	int nlines;
-	int i;
-	struct ctdb_node_map_old *ret;
-
-	/* Allocate node map header */
-	ret = talloc_zero_size(mem_ctx, offsetof(struct ctdb_node_map_old, nodes));
-	if (ret == NULL) {
-		DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
-		return false;
-	}
-
-	lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
-	if (lines == NULL) {
-		DEBUG(DEBUG_ERR, ("Failed to read nodes file \"%s\"\n", nlist));
-		return false;
-	}
-	while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
-		nlines--;
-	}
-
-	for (i=0; i < nlines; i++) {
-		char *node;
-		uint32_t flags;
-		size_t len;
-
-		node = lines[i];
-		/* strip leading spaces */
-		while((*node == ' ') || (*node == '\t')) {
-			node++;
-		}
-
-		len = strlen(node);
-
-		while ((len > 1) &&
-		       ((node[len-1] == ' ') || (node[len-1] == '\t')))
-		{
-			node[len-1] = '\0';
-			len--;
-		}
-
-		if (len == 0) {
-			continue;
-		}
-		if (*node == '#') {
-			/* A "deleted" node is a node that is
-			   commented out in the nodes file.  This is
-			   used instead of removing a line, which
-			   would cause subsequent nodes to change
-			   their PNN. */
-			flags = NODE_FLAGS_DELETED;
-			node = discard_const("0.0.0.0");
-		} else {
-			flags = 0;
-		}
-		if (!node_map_add(mem_ctx, node, flags, &ret)) {
-			talloc_free(lines);
-			TALLOC_FREE(ret);
-			return NULL;
-		}
-	}
-
-	talloc_free(lines);
-	return ret;
-}
-
 struct ctdb_node_map_old *
 ctdb_node_list_to_map(struct ctdb_node **nodes, uint32_t num_nodes,
 		      TALLOC_CTX *mem_ctx)
diff --git a/ctdb/conf/node.c b/ctdb/conf/node.c
new file mode 100644
index 00000000000..082b68b0d71
--- /dev/null
+++ b/ctdb/conf/node.c
@@ -0,0 +1,194 @@
+/*
+   Node file loading
+
+   Copyright (C) Martin Andrew Tridgell  2007
+   Copyright (C) Martin Ronnie Sahlberg  2008, 2009
+   Copyright (C) Martin Schwenke  2015
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_NODE_H__
+#define __CTDB_NODE_H__
+
+#include "replace.h"
+#include "system/network.h"
+
+#include <talloc.h>
+
+#include "lib/util/util_file.h"
+
+#include "protocol/protocol.h"
+#include "protocol/protocol_util.h"
+
+#include "conf/node.h"
+
+
+/* If unset, set port in address to the CTDB port */
+static void node_set_port(ctdb_sock_addr *address)
+{
+	struct servent *se = NULL;
+	unsigned int port;
+
+	port = ctdb_sock_addr_port(address);
+	if (port != 0) {
+		return;
+	}
+
+	setservent(0);
+	se = getservbyname("ctdb", "tcp");
+	endservent();
+
+	if (se == NULL) {
+		port = CTDB_PORT;
+	} else {
+		port = ntohs(se->s_port);
+	}
+
+	ctdb_sock_addr_set_port(address, port);
+}
+
+/* Append a node to a node map with given address and flags */
+static bool node_map_add(struct ctdb_node_map *nodemap,
+			 const char *nstr,
+			 uint32_t flags)
+{
+	ctdb_sock_addr addr = {};
+	uint32_t num;
+	struct ctdb_node_and_flags *n = NULL;
+	bool ok;
+
+	ok = ctdb_parse_node_address(nstr, &addr);
+	if (!ok) {
+		fprintf(stderr, "Invalid node address %s\n", nstr);
+		return false;
+	}
+
+	num = nodemap->num;
+	n = talloc_realloc(nodemap,
+			   nodemap->node,
+			   struct ctdb_node_and_flags,
+			   num + 1);
+	if (n == NULL) {
+		return false;
+	}
+	nodemap->node = n;
+
+	n = &nodemap->node[num];
+	n->addr = addr;
+	n->pnn = num;
+	n->flags = flags;
+
+	nodemap->num = num + 1;
+	return true;
+}
+
+/* Read a nodes file into a node map */
+static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
+						  const char *nlist)
+{
+	char **lines = NULL;
+	int nlines;
+	int i;
+	struct ctdb_node_map *nodemap = NULL;
+
+	nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
+	if (nodemap == NULL) {
+		return NULL;
+	}
+
+	lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
+	if (lines == NULL) {
+		return NULL;
+	}
+
+	while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
+		nlines--;
+	}
+
+	for (i = 0; i < nlines; i++) {
+		char *line;
+		const char *node = NULL;
+		uint32_t flags;
+		size_t len;
+
+		line = lines[i];
+		/* strip leading spaces */
+		while((*line == ' ') || (*line == '\t')) {
+			line++;
+		}
+
+		len = strlen(line);
+
+		/* strip trailing spaces */
+		while (len > 1 &&
+		       (line[len - 1] == ' ' || line[len - 1] == '\t')) {
+
+			line[len - 1] = '\0';
+			len--;
+		}
+
+		if (len == 0) {
+			continue;
+		}
+		if (*line == '#') {
+			/*
+			 * A "deleted" node is a node that is
+			 * commented out in the nodes file.  This is
+			 * used instead of removing a line, which
+			 * would cause subsequent nodes to change
+			 * their PNN.
+			 */
+			flags = NODE_FLAGS_DELETED;
+			node = "0.0.0.0";
+		} else {
+			flags = 0;
+			node = line;
+		}
+		if (!node_map_add(nodemap, node, flags)) {
+			talloc_free(lines);
+			TALLOC_FREE(nodemap);
+			return NULL;
+		}
+	}
+
+	talloc_free(lines);
+	return nodemap;
+}
+
+bool ctdb_parse_node_address(const char *str, ctdb_sock_addr *address)
+{
+	int ret;
+
+	ret = ctdb_sock_addr_from_string(str, address, false);
+	if (ret != 0) {
+		return false;
+	}
+	node_set_port(address);
+
+	return true;
+}
+
+struct ctdb_node_map *ctdb_read_nodes(TALLOC_CTX *mem_ctx,
+				      const char *location)
+{
+	struct ctdb_node_map* nodemap = NULL;
+
+	nodemap = ctdb_read_nodes_file(mem_ctx, location);
+
+	return nodemap;
+}
+
+#endif /* __CTDB_NODE_H__ */
diff --git a/ctdb/conf/node.h b/ctdb/conf/node.h
new file mode 100644
index 00000000000..cb1578ae726
--- /dev/null
+++ b/ctdb/conf/node.h
@@ -0,0 +1,54 @@
+/*
+   Node file loading
+
+   Copyright (C) Martin Andrew Tridgell  2007
+   Copyright (C) Martin Ronnie Sahlberg  2008, 2009
+   Copyright (C) Martin Schwenke  2015
+   Copyright (C) Amitay Isaacs  2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CTDB_COMMON_NODES_H__
+#define __CTDB_COMMON_NODES_H__
+
+#include <talloc.h>
+
+#include "protocol/protocol.h"
+
+/**
+ * @brief Parse node address string, setting CTDB port
+ *
+ * Parse a node address string.  Set the port number to the CTDB port.
+ *
+ * @param[in] str Text node address
+ * @param[out] address Socket address structure, already allocated
+ * @return true on success, false on failure
+ */
+bool ctdb_parse_node_address(const char *str, ctdb_sock_addr *address);
+
+/**
+ * @brief Load node list into a node map
+ *
+ * Load nodes from location, into a node map, allocated off the given
+ * talloc context.  Location must be a filename.
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] location Location of nodes list
+ * @return node map on success, NULL on failure
+ */
+struct ctdb_node_map *ctdb_read_nodes(TALLOC_CTX *mem_ctx,
+				      const char *location);
+
+#endif /* __CTDB_COMMON_NODES_H__ */
diff --git a/ctdb/include/ctdb_protocol.h b/ctdb/include/ctdb_protocol.h
index bec849e857c..3120103a48a 100644
--- a/ctdb/include/ctdb_protocol.h
+++ b/ctdb/include/ctdb_protocol.h
@@ -23,9 +23,6 @@
 #include <sys/socket.h>
 #include "protocol/protocol.h"
 
-/* define ctdb port number */
-#define CTDB_PORT 4379
-
 /* we must align packets to ensure ctdb works on all architectures (eg. sparc) */
 #define CTDB_DS_ALIGNMENT 8
 
diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h
index 99440b39125..c775c4bcc64 100644
--- a/ctdb/protocol/protocol.h
+++ b/ctdb/protocol/protocol.h
@@ -22,6 +22,8 @@
 
 #include <tdb.h>
 
+#define CTDB_PORT 4379
+
 #define CTDB_MAGIC	0x43544442 /* CTDB */
 #define CTDB_PROTOCOL	1
 
diff --git a/ctdb/protocol/protocol_api.h b/ctdb/protocol/protocol_api.h
index 6cc47a43980..c7aa94fe9bc 100644
--- a/ctdb/protocol/protocol_api.h
+++ b/ctdb/protocol/protocol_api.h
@@ -34,6 +34,11 @@ int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen,
 
 int ctdb_ltdb_header_extract(TDB_DATA *data, struct ctdb_ltdb_header *header);
 
+size_t ctdb_node_map_len(struct ctdb_node_map *in);
+void ctdb_node_map_push(struct ctdb_node_map *in, uint8_t *buf, size_t *npush);
+int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
+		       struct ctdb_node_map **out, size_t *npull);
+
 size_t ctdb_rec_data_len(struct ctdb_rec_data *in);
 void ctdb_rec_data_push(struct ctdb_rec_data *in, uint8_t *buf, size_t *npush);
 int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
diff --git a/ctdb/protocol/protocol_private.h b/ctdb/protocol/protocol_private.h
index cbbba394df7..350c670150e 100644
--- a/ctdb/protocol/protocol_private.h
+++ b/ctdb/protocol/protocol_private.h
@@ -214,11 +214,6 @@ void ctdb_node_and_flags_push(struct ctdb_node_and_flags *in, uint8_t *buf,
 int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
 			     struct ctdb_node_and_flags **out, size_t *npull);
 
-size_t ctdb_node_map_len(struct ctdb_node_map *in);
-void ctdb_node_map_push(struct ctdb_node_map *in, uint8_t *buf, size_t *npush);
-int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
-		       struct ctdb_node_map **out, size_t *npull);
-
 size_t ctdb_script_len(struct ctdb_script *in);
 void ctdb_script_push(struct ctdb_script *in, uint8_t *buf, size_t *npush);
 int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c
index c5dd1ed60aa..97dfc80ffd1 100644
--- a/ctdb/server/ctdb_daemon.c
+++ b/ctdb/server/ctdb_daemon.c
@@ -40,6 +40,9 @@


-- 
Samba Shared Repository



More information about the samba-cvs mailing list