All of lore.kernel.org
 help / color / mirror / Atom feed
* [bryder_autofs_4.1.4_PATCH 1/8] Added the dumpmap option and updated manpage
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
@ 2010-12-14  0:44 ` Bill Ryder
  2010-12-14  2:36 ` [bryder_autofs_4.1.4_PATCH 2/8] Set LDAP_DEPRECATED to prevent coredumps with modern ldap libraries Bill Ryder
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2010-12-14  0:44 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG           |    8 ++++++++
 daemon/automount.c  |   21 +++++++++++++++++++--
 include/automount.h |    3 +++
 lib/cache.c         |   10 ++++++++++
 man/automount.8     |    3 +++
 5 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index e9dbb63..467e90a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,11 @@
+16/6/2010 autofs-4.1.4 - bryder p37
+-------------------------
+Moved the autofs-4.1.3 version of the dump map patch to 4.1.4 (without the lookup_files hack)
+It adds the --dumpmap or -D argument to dump maps read by the daemon - then the daemon exits. 
+Also help to the automount.c command for this option and updated the man page.
+Only tested with LDAP.
+
+
 11/4/2005 autofs-4.1.4
 ----------------------
 - add /proc/modules check to Debian init script.
diff --git a/daemon/automount.c b/daemon/automount.c
index bbcab6a..93e3ff7 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -55,6 +55,7 @@ static char *pid_file = NULL;	/* File in which to keep pid */
 
 int kproto_version;		/* Kernel protocol version used */
 int kproto_sub_version = 0;	/* Kernel protocol version used */
+int dumpmap = 0;		/* cmdline arg to dump map contents */
 
 static int submount = 0;
 
@@ -1380,6 +1381,8 @@ static unsigned long getnumopt(char *str, char option)
 static void usage(void)
 {
 	fprintf(stderr, "Usage: %s [options] path map_type [args...]\n", program);
+	fprintf(stderr, "   -D|--dumpmap dumps out the maps read and exits\n");
+
 }
 
 static void setup_signals(__sighandler_t event_handler, __sighandler_t cld_handler)
@@ -1671,6 +1674,7 @@ int main(int argc, char *argv[])
 		{"version", 0, 0, 'V'},
 		{"ghost", 0, 0, 'g'},
 		{"submount", 0, &submount, 1},
+		{"dumpmap", 0, 0, 'D'},
 		{0, 0, 0, 0}
 	};
 
@@ -1683,7 +1687,7 @@ int main(int argc, char *argv[])
 	ap.dir_created = 0; /* We haven't created the main directory yet */
 
 	opterr = 0;
-	while ((opt = getopt_long(argc, argv, "+hp:t:vdVg", long_options, NULL)) != EOF) {
+	while ((opt = getopt_long(argc, argv, "+hp:t:vdVgD", long_options, NULL)) != EOF) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -1713,6 +1717,9 @@ int main(int argc, char *argv[])
 			ap.ghost = LKP_GHOST;
 			break;
 
+		case 'D':
+			dumpmap = 1;
+			break;
 		case '?':
 		case ':':
 			printf("%s: Ambiguous or unknown options\n", program);
@@ -1734,7 +1741,8 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	become_daemon();
+	if (!dumpmap)
+		become_daemon();
 
 	path = argv[0];
 	map = argv[1];
@@ -1762,6 +1770,15 @@ int main(int argc, char *argv[])
 	if (!(ap.lookup = open_lookup(map, "", mapfmt, mapargc, mapargv)))
 		cleanup_exit(path, 1);
 
+	if (dumpmap) {
+		int ret;
+		ret = ap.lookup->lookup_ghost(ap.path, ap.ghost,
+					      0, ap.lookup->context);
+		if (ret & LKP_FAIL)
+			exit(ret);
+		exit(0);
+	}
+
 	if (!strncmp(path, "/-", 2)) {
 		supervisor(path);
 	} else {
diff --git a/include/automount.h b/include/automount.h
index d2f5d70..64ff83d 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -286,6 +286,9 @@ int allow_owner_mount(const char *);
 extern int do_verbose;
 extern int do_debug;
 
+/* command line option to print out included map contents */
+extern int dumpmap;
+
 #define info(msg, args...) 		\
 if (do_verbose || do_debug) 		\
 	syslog(LOG_INFO, msg, ##args);
diff --git a/lib/cache.c b/lib/cache.c
index 781c980..5a01079 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -169,6 +169,11 @@ int cache_add(const char *root, const char *key, const char *mapent, time_t age)
 	char *pkey, *pent;
 	unsigned int hashval = hash(key);
 
+	if (dumpmap) {
+		fprintf(stdout, "%s %s\n", key, mapent);
+		return CHE_OK;
+	}
+
 	me = (struct mapent_cache *) malloc(sizeof(struct mapent_cache));
 	if (!me)
 		return CHE_FAIL;
@@ -221,6 +226,11 @@ int cache_update(const char *root, const char *key, const char *mapent, time_t a
 	char *pent;
 	int ret = CHE_OK;
 
+	if (dumpmap) {
+		fprintf(stdout, "%s %s\n", key, mapent);
+		return CHE_OK;
+	}
+
 	for (s = mapent_hash[hash(key)]; s != NULL; s = s->next)
 		if (strcmp(key, s->key) == 0)
 			me = s;
diff --git a/man/automount.8 b/man/automount.8
index 2b63959..e640656 100644
--- a/man/automount.8
+++ b/man/automount.8
@@ -43,6 +43,9 @@ until accesssed. The wildcard map is not ghosted.
 .TP
 .I "\-V, \-\-version"
 Display the version number, then exit.
+.TP
+.I "\-D, \-\-dumpmap"
+Dumps the maps read and exits.
 .SH ARGUMENTS
 \fBautomount\fP takes at least three arguments.  Mandatory arguments 
 include \fImount-point\fP, \fImap-type\fP, and \fImap\fP.  Both mandatory
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 2/8] Set LDAP_DEPRECATED to prevent coredumps with modern ldap libraries
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
  2010-12-14  0:44 ` [bryder_autofs_4.1.4_PATCH 1/8] Added the dumpmap option and updated manpage Bill Ryder
@ 2010-12-14  2:36 ` Bill Ryder
  2010-12-20  1:10 ` [bryder_autofs_4.1.4_PATCH 3/8] Added function names to some debug/crit messages, changed some crits to debug Bill Ryder
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2010-12-14  2:36 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG        |    5 +++++
 configure.in     |    1 +
 samples/Makefile |    2 +-
 3 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 467e90a..9dd8185 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+17/6/2010 autofs-4.1.4 - bryder p38
+---------------------------
+Added LDAP patch to stop the autofs-ldap-auto-master and lookup_ldap.so from crashing on modern ldap libraries. 
+It sets the LDAP_DEPRECATED macro to 1. Obviously the ldap stuff needs some updating.
+
 16/6/2010 autofs-4.1.4 - bryder p37
 -------------------------
 Moved the autofs-4.1.3 version of the dump map patch to 4.1.4 (without the lookup_files hack)
diff --git a/configure.in b/configure.in
index eb56ac7..623e92b 100644
--- a/configure.in
+++ b/configure.in
@@ -118,6 +118,7 @@ AC_ARG_WITH(openldap,
 )
 if test -z "$HAVE_LDAP"; then
 	HAVE_LDAP=0
+	LDAP_FLAGS="$LDAP_FLAGS -DLDAP_DEPRECATED=1"
 	AC_CHECK_LIB(ldap, ldap_init, HAVE_LDAP=1 LIBLDAP="$LIBLDAP -lldap -llber -lresolv", ,
 		     -llber -lresolv $LIBS)
 fi
diff --git a/samples/Makefile b/samples/Makefile
index d69d6e7..f5aa2ba 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -16,7 +16,7 @@ LIBS = -lldap -llber
 all: $(BINS) rc.autofs
 
 autofs-ldap-auto-master: $(OBJS)
-	$(CC) $(LDFLAGS) -o autofs-ldap-auto-master $(OBJS) $(LIBS)
+	$(CC) $(LDFLAGS) $(LDAP_FLAGS) -o autofs-ldap-auto-master $(OBJS) $(LIBS)
 	$(STRIP) autofs-ldap-auto-master
 
 rc.autofs: rc.autofs.in
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 3/8] Added function names to some debug/crit messages, changed some crits to debug
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
  2010-12-14  0:44 ` [bryder_autofs_4.1.4_PATCH 1/8] Added the dumpmap option and updated manpage Bill Ryder
  2010-12-14  2:36 ` [bryder_autofs_4.1.4_PATCH 2/8] Set LDAP_DEPRECATED to prevent coredumps with modern ldap libraries Bill Ryder
@ 2010-12-20  1:10 ` Bill Ryder
  2010-12-20 19:30 ` [bryder_autofs_4.1.4_PATCH 4/8] reinstated the jmoyer ldap-cleanup patch and included man etc updates Bill Ryder
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2010-12-20  1:10 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG             |   10 +++++++-
 modules/lookup_ldap.c |   64 +++++++++++++++++++++++++-----------------------
 2 files changed, 42 insertions(+), 32 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 9dd8185..c40a670 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,13 @@
+
+18/6/2010 autofs-4.1.4 - bryder p39
+-----------------------------------
+Added the function name to the lookup_ldap debug and critical messages. 
+Also made a couple of the 'crit' messages 'debug' messages because they are not actually critical. 
+They just show a failed search.
+
+
 17/6/2010 autofs-4.1.4 - bryder p38
----------------------------
+--------------------------
 Added LDAP patch to stop the autofs-ldap-auto-master and lookup_ldap.so from crashing on modern ldap libraries. 
 It sets the LDAP_DEPRECATED macro to 1. Obviously the ldap stuff needs some updating.
 
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index b269f75..f8ed7fc 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -80,7 +80,7 @@ static LDAP *do_connect(struct lookup_context *ctxt, int *result_ldap)
 	rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
 	if (rv != LDAP_SUCCESS) {
 		warn(MODPREFIX
-		     "failed to set connection timeout to %d", timeout);
+		     "%s: failed to set connection timeout to %d", __func__, timeout);
 	}
 
 	/* Connect to the server as an anonymous user. */
@@ -172,7 +172,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
 	memset(ctxt->base, 0, l + 1);
 	memcpy(ctxt->base, ptr, l);
 
-	debug(MODPREFIX "server = \"%s\", port = %d, base dn = \"%s\"",
+	debug(MODPREFIX "%s: server = \"%s\", port = %d, base dn = \"%s\"", __func__,
 		  ctxt->server ? ctxt->server : "(default)",
 		  ctxt->port, ctxt->base);
 
@@ -203,7 +203,7 @@ static int read_one_map(const char *root,
 	LDAP *ldap;
 
 	if (ctxt == NULL) {
-		crit(MODPREFIX "context was NULL");
+		crit(MODPREFIX "%s: context was NULL", __func__);
 		return 0;
 	}
 
@@ -223,11 +223,11 @@ static int read_one_map(const char *root,
 	if (keyvallen > 0) {
 		if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
 			    key, keyvallen, keyval) >= l) {
-			debug(MODPREFIX "error forming query string");
+			debug(MODPREFIX "%s: error forming query string", __func__);
 		}
 	} else {
 		if (sprintf(query, "(objectclass=%s)", class) >= l) {
-			debug(MODPREFIX "error forming query string");
+			debug(MODPREFIX "%s: error forming query string", __func__);
 		}
 	}
 	query[l - 1] = '\0';
@@ -238,13 +238,13 @@ static int read_one_map(const char *root,
 		return 0;
 
 	/* Look around. */
-	debug(MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->base);
+	debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, query, ctxt->base);
 
 	rv = ldap_search_s(ldap, ctxt->base, LDAP_SCOPE_SUBTREE,
 			   query, attrs, 0, &result);
 
 	if ((rv != LDAP_SUCCESS) || !result) {
-		crit(MODPREFIX "query failed for %s: %s", query, ldap_err2string(rv));
+	        crit(MODPREFIX "%s: query failed for %s: %s", __func__, query, ldap_err2string(rv));
 		ldap_unbind(ldap);
 		*result_ldap = rv;
 		return 0;
@@ -252,12 +252,12 @@ static int read_one_map(const char *root,
 
 	e = ldap_first_entry(ldap, result);
 	if (!e) {
-		debug(MODPREFIX "query succeeded, no matches for %s", query);
+		debug(MODPREFIX "%s: query succeeded, no matches for %s", __func__, query);
 		ldap_msgfree(result);
 		ldap_unbind(ldap);
 		return 0;
 	} else
-		debug(MODPREFIX "examining entries");
+		debug(MODPREFIX "%s: examining entries", __func__ );
 
 	while (e) {
 		keyValue = ldap_get_values(ldap, e, key);
@@ -269,7 +269,7 @@ static int read_one_map(const char *root,
 
 		values = ldap_get_values(ldap, e, type);
 		if (!values) {
-			info(MODPREFIX "no %s defined for %s", type, query);
+			info(MODPREFIX "%s: no %s defined for %s", __func__, type, query);
 			ldap_value_free(keyValue);
 			e = ldap_next_entry(ldap, e);
 			continue;
@@ -291,7 +291,7 @@ static int read_one_map(const char *root,
 		e = ldap_next_entry(ldap, e);
 	}
 
-	debug(MODPREFIX "done updating map");
+	debug(MODPREFIX "%s: done updating map", __func__ );
 
 	/* Clean up. */
 	ldap_msgfree(result);
@@ -393,7 +393,7 @@ static int lookup_one(const char *root, const char *qKey,
 	int ret = CHE_OK;
 
 	if (ctxt == NULL) {
-		crit(MODPREFIX "context was NULL");
+		crit(MODPREFIX "%s: context was NULL", __func__ );
 		return 0;
 	}
 
@@ -404,7 +404,7 @@ static int lookup_one(const char *root, const char *qKey,
 
 	query = alloca(l);
 	if (query == NULL) {
-		crit(MODPREFIX "malloc: %m");
+		crit(MODPREFIX "%s: alloca returned NULL", __func__ );
 		return 0;
 	}
 
@@ -412,12 +412,12 @@ static int lookup_one(const char *root, const char *qKey,
 	memset(query, '\0', l);
 	ql = sprintf(query, "(&(objectclass=%s)(%s=%s))", class, key, qKey);
 	if (ql >= l) {
-		debug(MODPREFIX "error forming query string");
+		debug(MODPREFIX "%s: error forming query string", __func__);
 		return 0;
 	}
 	query[l - 1] = '\0';
 
-	debug(MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->base);
+	debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, query, ctxt->base);
 
 	/* Initialize the LDAP context. */
 	ldap = do_connect(ctxt, &rv);
@@ -428,26 +428,27 @@ static int lookup_one(const char *root, const char *qKey,
 			   query, attrs, 0, &result);
 
 	if ((rv != LDAP_SUCCESS) || !result) {
-		crit(MODPREFIX "query failed for %s", query);
+		crit(MODPREFIX "%s: query failed for %s", __func__, query);
 		ldap_unbind(ldap);
 		return 0;
 	}
 
-	debug(MODPREFIX "getting first entry for %s=\"%s\"", key, qKey);
 
+	debug(MODPREFIX "%s: getting first entry for %s=\"%s\"", __func__, key, qKey);
 	e = ldap_first_entry(ldap, result);
 	if (!e) {
-		crit(MODPREFIX "got answer, but no first entry for %s", query);
+		debug(MODPREFIX "%s: got answer, but no first entry for %s", __func__, query);
 		ldap_msgfree(result);
 		ldap_unbind(ldap);
 		return CHE_MISSING;
 	}
 
-	debug(MODPREFIX "examining first entry");
+
+	debug(MODPREFIX "%s: examining first entry", __func__);
 
 	values = ldap_get_values(ldap, e, type);
 	if (!values) {
-		debug(MODPREFIX "no %s defined for %s", type, query);
+		debug(MODPREFIX "%s: no %s defined for %s", __func__, type, query);
 		ldap_msgfree(result);
 		ldap_unbind(ldap);
 		return CHE_MISSING;
@@ -499,7 +500,7 @@ static int lookup_wild(const char *root,
 	int qKey_len;
 
 	if (ctxt == NULL) {
-		crit(MODPREFIX "context was NULL");
+		crit(MODPREFIX "%s: context was NULL", __func__);
 		return 0;
 	}
 
@@ -512,7 +513,7 @@ static int lookup_wild(const char *root,
 
 	query = alloca(l);
 	if (query == NULL) {
-		crit(MODPREFIX "malloc: %m");
+		crit(MODPREFIX "%s: malloc failed",__func__);
 		return 0;
 	}
 
@@ -520,12 +521,12 @@ static int lookup_wild(const char *root,
 	memset(query, '\0', l);
 	ql = sprintf(query, "(&(objectclass=%s)(%s=%s))", class, key, qKey);
 	if (ql >= l) {
-		debug(MODPREFIX "error forming query string");
+		debug(MODPREFIX "%s: error forming query string", __func__);
 		return 0;
 	}
 	query[l - 1] = '\0';
 
-	debug(MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->base);
+	debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, query, ctxt->base);
 
 	/* Initialize the LDAP context. */
 	ldap = do_connect(ctxt, &rv);
@@ -536,26 +537,27 @@ static int lookup_wild(const char *root,
 			   query, attrs, 0, &result);
 
 	if ((rv != LDAP_SUCCESS) || !result) {
-		crit(MODPREFIX "query failed for %s", query);
+		crit(MODPREFIX "%s: query failed for %s", __func__, query);
 		ldap_unbind(ldap);
 		return 0;
 	}
 
-	debug(MODPREFIX "getting first entry for %s=\"%s\"", key, qKey);
+
+	debug(MODPREFIX "%s: getting first entry for %s=\"%s\"", __func__, key, qKey);
 
 	e = ldap_first_entry(ldap, result);
 	if (!e) {
-		crit(MODPREFIX "got answer, but no first entry for %s", query);
+		debug(MODPREFIX "%s: got answer, but no first entry for %s", __func__, query);
 		ldap_msgfree(result);
 		ldap_unbind(ldap);
 		return CHE_MISSING;
 	}
 
-	debug(MODPREFIX "examining first entry");
+	debug(MODPREFIX "%s: examining first entry", __func__);
 
 	values = ldap_get_values(ldap, e, type);
 	if (!values) {
-		debug(MODPREFIX "no %s defined for %s", type, query);
+		debug(MODPREFIX "%s: no %s defined for %s", __func__, type, query);
 		ldap_msgfree(result);
 		ldap_unbind(ldap);
 		return CHE_MISSING;
@@ -654,7 +656,7 @@ int lookup_mount(const char *root, const char *name, int name_len, void *context
 		while (me) {
 			sprintf(mapent, me->mapent);
 
-			debug(MODPREFIX "%s -> %s", key, mapent);
+			debug(MODPREFIX "%s: %s -> %s", __func__, key, mapent);
 			ret = ctxt->parse->parse_mount(root, name, name_len,
 						  mapent, ctxt->parse->context);
 			me = cache_lookup_next(me);
@@ -674,7 +676,7 @@ int lookup_mount(const char *root, const char *name, int name_len, void *context
 			}
 			sprintf(mapent, "-fstype=autofs ldap:%s", mapname);
 
-			debug(MODPREFIX "%s -> %s", key, mapent);
+			debug(MODPREFIX "%s: %s -> %s", __func__, key, mapent);
 			ret = ctxt->parse->parse_mount(root, name, name_len,
 						  mapent, ctxt->parse->context);
 		}
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 4/8] reinstated the jmoyer ldap-cleanup patch and included man etc updates
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
                   ` (2 preceding siblings ...)
  2010-12-20  1:10 ` [bryder_autofs_4.1.4_PATCH 3/8] Added function names to some debug/crit messages, changed some crits to debug Bill Ryder
@ 2010-12-20 19:30 ` Bill Ryder
  2011-01-10  1:27 ` [bryder_autofs_4.1.4_PATCH 5/8] Added option to ignore some highly unlikely paths before forking daemon Bill Ryder
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2010-12-20 19:30 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG             |    9 ++
 daemon/automount.c    |    8 +-
 include/automount.h   |    1 +
 man/automount.8       |    8 ++
 modules/lookup_ldap.c |  275 ++++++++++++++++++++++++++++++++-----------------
 5 files changed, 206 insertions(+), 95 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index c40a670..04043c5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,10 @@
+29/06/2010 autofs-4.1.4-p40
+---------------------------
+  Reinstates the jmoyer ldap-cleanup.patch from 4.1.3 which does cleaner LDAP schema handling. 
+  It only looks up the schema once and then remembers it for every requested path under a mount point.
+  It  includes the --use_old_ldap_lookup or -u option to make the code search every schema every time the way it used to.
+  bryder changed the original patch is to invert the search order so the most modern schema (rfc2307bis) is checked first
+  bryder added the option to the man page and help output from automount.c
 
 18/6/2010 autofs-4.1.4 - bryder p39
 -----------------------------------
@@ -19,6 +26,8 @@ Also help to the automount.c command for this option and updated the man page.
 Only tested with LDAP.
 
 
+
+
 11/4/2005 autofs-4.1.4
 ----------------------
 - add /proc/modules check to Debian init script.
diff --git a/daemon/automount.c b/daemon/automount.c
index 93e3ff7..0ef9cbb 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1382,7 +1382,7 @@ static void usage(void)
 {
 	fprintf(stderr, "Usage: %s [options] path map_type [args...]\n", program);
 	fprintf(stderr, "   -D|--dumpmap dumps out the maps read and exits\n");
-
+	fprintf(stderr, "   -u|--use-old-ldap-lookup instead of figuring out the schema once do it every single time a mount is requested. This is the old behaviour\n");
 }
 
 static void setup_signals(__sighandler_t event_handler, __sighandler_t cld_handler)
@@ -1675,6 +1675,7 @@ int main(int argc, char *argv[])
 		{"ghost", 0, 0, 'g'},
 		{"submount", 0, &submount, 1},
 		{"dumpmap", 0, 0, 'D'},
+		{"use-old-ldap-lookup", 0, 0, 'u'},
 		{0, 0, 0, 0}
 	};
 
@@ -1687,7 +1688,7 @@ int main(int argc, char *argv[])
 	ap.dir_created = 0; /* We haven't created the main directory yet */
 
 	opterr = 0;
-	while ((opt = getopt_long(argc, argv, "+hp:t:vdVgD", long_options, NULL)) != EOF) {
+	while ((opt = getopt_long(argc, argv, "+hp:t:vdVgDu", long_options, NULL)) != EOF) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -1720,6 +1721,9 @@ int main(int argc, char *argv[])
 		case 'D':
 			dumpmap = 1;
 			break;
+		case 'u':
+			ap.use_old_ldap_lookup = 1;
+			break;
 		case '?':
 		case ':':
 			printf("%s: Ambiguous or unknown options\n", program);
diff --git a/include/automount.h b/include/automount.h
index 64ff83d..fa97764 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -113,6 +113,7 @@ struct autofs_point {
 	int state_pipe[2];
 	unsigned dir_created;		/* Was a directory created for this
 					   mount? */
+	unsigned use_old_ldap_lookup;   /* query all schemas every time instead of sticking with the first one found */
 };
 
 extern struct autofs_point ap; 
diff --git a/man/automount.8 b/man/automount.8
index e640656..5dc597b 100644
--- a/man/automount.8
+++ b/man/automount.8
@@ -46,6 +46,14 @@ Display the version number, then exit.
 .TP
 .I "\-D, \-\-dumpmap"
 Dumps the maps read and exits.
+.TP
+.I "\-u, \-\-use\-old\-ldap\-lookup"
+By default automount will use new code for finding the correct ldap
+schema. It starts with rfc2307bis, then does the netscape one, then
+the original rfc2307 schema. It only checks once for each mount point
+and remembers the schema for the rest of the automount invocation.
+If you set this flag it will do it the old way which involves looking
+for the schema every time a mount is requested.
 .SH ARGUMENTS
 \fBautomount\fP takes at least three arguments.  Mandatory arguments 
 include \fImount-point\fP, \fImap-type\fP, and \fImap\fP.  Both mandatory
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index f8ed7fc..1c5c62a 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -39,14 +39,57 @@
 
 #define MODPREFIX "lookup(ldap): "
 
+/*
+ *  Automount entries are stored hierarchically, with the map name as the base
+ *  dn for searches on entries for that map.  Thus, to obtain the base dn for
+ *  the master map, one would use the following filter:
+ *    (&(objectclass=<map_object_class>)(<map_name_attr>="auto.master"))
+ *  Once the base dn is obtained (using ldap_get_first_entry, followed by
+ *  ldap_get_dn), the following filter will return all entries for the given
+ *  map:
+ *    (objectclass=<entry_object_class>)
+ *  The attributes of interest are <entry_key_attr>, or the key, and
+ *  <entry_value_attr> or the value portion of the automount map entry.
+ */
+struct autofs_schema {
+	char *map_object_class;
+	char *map_name_attr;
+
+	char *entry_object_class;
+	char *entry_key_attr;
+	char *entry_value_attr;
+};
+
+
+#define NR_SCHEMAS	3
+struct autofs_schema supported_schemas[NR_SCHEMAS] = {
+	{ "automountMap", "automountMapName",
+	  "automount", "automountKey", "automountInformation" },
+	{ "automountMap", "ou", "automount", "cn", "automountInformation" },
+	{ "nisMap", "nisMapName", "nisObject", "cn", "nisMapEntry" },
+};
+
 struct lookup_context {
 	char *server, *base;
 	int port;
+
+	/* once we find a schema that works, save it for future lookups  -
+	 * unless the use_old_ldap_lookup optoin is in effect in which case every schema is search every time.
+	 */
+	struct autofs_schema *schema;
+
 	struct parse_mod *parse;
 };
 
 int lookup_version = AUTOFS_LOOKUP_VERSION;	/* Required by protocol */
 
+void set_schema(struct lookup_context *ctxt, struct autofs_schema *schema)
+{
+	if (!ap.use_old_ldap_lookup) 
+		ctxt->schema = schema;
+}
+
+
 static LDAP *do_connect(struct lookup_context *ctxt, int *result_ldap)
 {
 	LDAP *ldap;
@@ -57,8 +100,8 @@ static LDAP *do_connect(struct lookup_context *ctxt, int *result_ldap)
 	/* Initialize the LDAP context. */
 	ldap = ldap_init(ctxt->server, ctxt->port);
 	if (!ldap) {
-		crit(MODPREFIX "couldn't initialize LDAP connection"
-		     " to %s", ctxt->server ? ctxt->server : "default server");
+		crit(MODPREFIX "%s: couldn't initialize LDAP connection"
+		     " to %s", __func__, ctxt->server ? ctxt->server : "default server");
 		return NULL;
 	}
 
@@ -69,7 +112,7 @@ static LDAP *do_connect(struct lookup_context *ctxt, int *result_ldap)
 		ldap_unbind(ldap);
 		ldap = ldap_init(ctxt->server, ctxt->port);
 		if (!ldap) {
-			crit(MODPREFIX "couldn't initialize LDAP");
+			crit(MODPREFIX "%s: couldn't initialize LDAP for v2", __func__ );
 			return NULL;
 		} else {
 			version = 2;
@@ -79,7 +122,7 @@ static LDAP *do_connect(struct lookup_context *ctxt, int *result_ldap)
 	/* Sane network connection timeout */
 	rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
 	if (rv != LDAP_SUCCESS) {
-		warn(MODPREFIX
+		warn(MODPREFIX 
 		     "%s: failed to set connection timeout to %d", __func__, timeout);
 	}
 
@@ -188,9 +231,8 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
 	return !(ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1));
 }
 
-static int read_one_map(const char *root,
-			const char *class, char *key,
-			const char *keyval, int keyvallen, char *type,
+static int read_one_map(LDAP *ldap, const char *root,
+			struct autofs_schema *schema,			
 			struct lookup_context *ctxt,
 			time_t age, int *result_ldap)
 {
@@ -199,8 +241,13 @@ static int read_one_map(const char *root,
 	LDAPMessage *result, *e;
 	char **keyValue = NULL;
 	char **values = NULL;
-	char *attrs[] = { key, type, NULL };
-	LDAP *ldap;
+	char *attrs[] = { schema->entry_key_attr,
+			  schema->entry_value_attr,
+			  NULL };
+	const char *class = schema->entry_object_class,
+		   *key = schema->entry_key_attr,
+		   *type = schema->entry_value_attr;
+	int found_entry = 0;
 
 	if (ctxt == NULL) {
 		crit(MODPREFIX "%s: context was NULL", __func__);
@@ -209,9 +256,6 @@ static int read_one_map(const char *root,
 
 	/* Build a query string. */
 	l = strlen("(objectclass=)") + strlen(class) + 1;
-	if (keyvallen > 0) {
-		l += strlen(key) +keyvallen + strlen("(&(=))");
-	}
 
 	query = alloca(l);
 	if (query == NULL) {
@@ -220,22 +264,11 @@ static int read_one_map(const char *root,
 	}
 
 	memset(query, '\0', l);
-	if (keyvallen > 0) {
-		if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
-			    key, keyvallen, keyval) >= l) {
-			debug(MODPREFIX "%s: error forming query string", __func__);
-		}
-	} else {
-		if (sprintf(query, "(objectclass=%s)", class) >= l) {
-			debug(MODPREFIX "%s: error forming query string", __func__);
-		}
+	if (sprintf(query, "(objectclass=%s)", class) >= l) {
+		debug(MODPREFIX "error forming query string");
 	}
 	query[l - 1] = '\0';
 
-	/* Initialize the LDAP context. */
-	ldap = do_connect(ctxt, result_ldap);
-	if (!ldap)
-		return 0;
 
 	/* Look around. */
 	debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, query, ctxt->base);
@@ -245,7 +278,6 @@ static int read_one_map(const char *root,
 
 	if ((rv != LDAP_SUCCESS) || !result) {
 	        crit(MODPREFIX "%s: query failed for %s: %s", __func__, query, ldap_err2string(rv));
-		ldap_unbind(ldap);
 		*result_ldap = rv;
 		return 0;
 	}
@@ -254,7 +286,6 @@ static int read_one_map(const char *root,
 	if (!e) {
 		debug(MODPREFIX "%s: query succeeded, no matches for %s", __func__, query);
 		ldap_msgfree(result);
-		ldap_unbind(ldap);
 		return 0;
 	} else
 		debug(MODPREFIX "%s: examining entries", __func__ );
@@ -267,6 +298,8 @@ static int read_one_map(const char *root,
 			continue;
 		}
 
+		found_entry = 1;
+
 		values = ldap_get_values(ldap, e, type);
 		if (!values) {
 			info(MODPREFIX "%s: no %s defined for %s", __func__, type, query);
@@ -295,37 +328,55 @@ static int read_one_map(const char *root,
 
 	/* Clean up. */
 	ldap_msgfree(result);
-	ldap_unbind(ldap);
 
-	return 1;
+	if (found_entry) 
+		return 1;
+	else
+		return 0;
 }
 
 static int read_map(const char *root, struct lookup_context *ctxt,
-		    const char *key, int keyvallen, time_t age, int *result_ldap)
+		    time_t age, int *result_ldap)
 {
-	int rv1 = LDAP_SUCCESS, rv2 = LDAP_SUCCESS;
-	int ret;
-
-	/* all else fails read entire map */
-	ret = read_one_map(root, "nisObject", "cn", 
-			  key, keyvallen, "nisMapEntry", ctxt, age, &rv1);
-	if (ret)
-		goto ret_ok;
+	LDAP *ldap;
+	int rv = LDAP_SUCCESS;
+	int ret, i;
 
-	ret = read_one_map(root, "automount", "cn", key, keyvallen, 
-			  "automountInformation", ctxt, age, &rv2);
-	if (ret)
-		goto ret_ok;
+	/* Initialize the LDAP context. */
+	ldap = do_connect(ctxt, &rv);
+	if (!ldap) {
+		if (rv != LDAP_SUCCESS)
+			*result_ldap = rv;
+		return 0;
+	}
 
+	/* all else fails read entire map */
+	if (ctxt->schema) {
+		ret = read_one_map(ldap, root, ctxt->schema, ctxt, age, &rv);
+		if (ret == 1 && rv == LDAP_SUCCESS)
+			goto ret_ok;
+	} else {
+		for (i = 0; i < NR_SCHEMAS; i++) {
+			ret = read_one_map(ldap, root,
+					   &supported_schemas[i],
+					   ctxt, age, &rv);
+			if (ret == 1 && rv == LDAP_SUCCESS) {
+				set_schema(ctxt, &supported_schemas[i]);
+				goto ret_ok;
+			}
+		}
+	}
+ 
+	ldap_unbind(ldap);
 	if (result_ldap)
-		*result_ldap = (rv1 == LDAP_SUCCESS ? rv2 : rv1);
+		*result_ldap = rv;
 
 	return 0;
 
 ret_ok:
 	/* Clean stale entries from the cache */
 	cache_clean(root, age);
-
+	ldap_unbind(ldap);
 	return 1;
 }
 
@@ -339,7 +390,7 @@ int lookup_ghost(const char *root, int ghost, time_t now, void *context)
 
 	chdir("/");
 
-	if (!read_map(root, ctxt, NULL, 0, age, &rv))
+	if (!read_map(root, ctxt, age, &rv))
 		switch (rv) {
 		case LDAP_SIZELIMIT_EXCEEDED:
 		case LDAP_UNWILLING_TO_PERFORM:
@@ -378,17 +429,21 @@ int lookup_ghost(const char *root, int ghost, time_t now, void *context)
 	return status;
 }
 
-static int lookup_one(const char *root, const char *qKey,
-		      const char *class, char *key, char *type,
-		      struct lookup_context *ctxt)
+static int lookup_one_schema(LDAP *ldap, const char *root, const char *qKey,
+			     struct autofs_schema *schema,
+			     struct lookup_context *ctxt)
 {
 	int rv, i, l, ql;
 	time_t age = time(NULL);
 	char *query;
 	LDAPMessage *result, *e;
 	char **values = NULL;
-	char *attrs[] = { key, type, NULL };
-	LDAP *ldap;
+	char *attrs[] = { schema->entry_key_attr,
+			  schema->entry_value_attr,
+			  NULL };
+	const char *class = schema->entry_object_class,
+		   *key = schema->entry_key_attr,
+		   *type = schema->entry_value_attr;
 	struct mapent_cache *me = NULL;
 	int ret = CHE_OK;
 
@@ -419,38 +474,29 @@ static int lookup_one(const char *root, const char *qKey,
 
 	debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, query, ctxt->base);
 
-	/* Initialize the LDAP context. */
-	ldap = do_connect(ctxt, &rv);
-	if (!ldap)
-		return 0;
-
 	rv = ldap_search_s(ldap, ctxt->base, LDAP_SCOPE_SUBTREE,
 			   query, attrs, 0, &result);
 
 	if ((rv != LDAP_SUCCESS) || !result) {
 		crit(MODPREFIX "%s: query failed for %s", __func__, query);
-		ldap_unbind(ldap);
 		return 0;
 	}
 
-
 	debug(MODPREFIX "%s: getting first entry for %s=\"%s\"", __func__, key, qKey);
+
 	e = ldap_first_entry(ldap, result);
 	if (!e) {
 		debug(MODPREFIX "%s: got answer, but no first entry for %s", __func__, query);
 		ldap_msgfree(result);
-		ldap_unbind(ldap);
 		return CHE_MISSING;
 	}
 
-
 	debug(MODPREFIX "%s: examining first entry", __func__);
 
 	values = ldap_get_values(ldap, e, type);
 	if (!values) {
 		debug(MODPREFIX "%s: no %s defined for %s", __func__, type, query);
 		ldap_msgfree(result);
-		ldap_unbind(ldap);
 		return CHE_MISSING;
 	}
 
@@ -478,22 +524,51 @@ static int lookup_one(const char *root, const char *qKey,
 	/* Clean up. */
 	ldap_value_free(values);
 	ldap_msgfree(result);
-	ldap_unbind(ldap);
 
 	return ret;
 }
 
-static int lookup_wild(const char *root,
-		      const char *class, char *key, char *type,
+static int lookup_one(LDAP *ldap, const char *root, const char *qKey,
 		      struct lookup_context *ctxt)
 {
+	int ret, i;
+
+	if (ctxt->schema) {
+		ret = lookup_one_schema(ldap, root, qKey, ctxt->schema, ctxt);
+		debug("lookup_one with schema %s,%s,%s returns %d\n",
+		      ctxt->schema->entry_key_attr,
+		      ctxt->schema->entry_object_class,
+		      ctxt->schema->entry_value_attr, ret);
+	} else {
+		for (i = 0; i < NR_SCHEMAS; i++) {
+			ret = lookup_one_schema(ldap, root, qKey,
+					 &supported_schemas[i], ctxt);
+			debug("lookup_one with schema %d returns %d\n",i, ret);
+			if (ret != CHE_FAIL) {
+				set_schema(ctxt, &supported_schemas[i]);
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int lookup_wild_schema(LDAP *ldap, const char *root,
+			      struct autofs_schema *schema,
+			      struct lookup_context *ctxt)
+{
 	int rv, i, l, ql;
 	time_t age = time(NULL);
 	char *query;
 	LDAPMessage *result, *e;
 	char **values = NULL;
-	char *attrs[] = { key, type, NULL };
-	LDAP *ldap;
+	char *attrs[] = { schema->entry_key_attr,
+			  schema->entry_value_attr,
+			  NULL };
+	const char *class = schema->entry_object_class,
+		   *key = schema->entry_key_attr,
+		   *type = schema->entry_value_attr;
 	struct mapent_cache *me = NULL;
 	int ret = CHE_OK;
 	char qKey[KEY_MAX_LEN + 1];
@@ -528,28 +603,20 @@ static int lookup_wild(const char *root,
 
 	debug(MODPREFIX "%s: searching for \"%s\" under \"%s\"", __func__, query, ctxt->base);
 
-	/* Initialize the LDAP context. */
-	ldap = do_connect(ctxt, &rv);
-	if (!ldap)
-		return 0;
-
 	rv = ldap_search_s(ldap, ctxt->base, LDAP_SCOPE_SUBTREE,
 			   query, attrs, 0, &result);
 
 	if ((rv != LDAP_SUCCESS) || !result) {
 		crit(MODPREFIX "%s: query failed for %s", __func__, query);
-		ldap_unbind(ldap);
 		return 0;
 	}
 
-
 	debug(MODPREFIX "%s: getting first entry for %s=\"%s\"", __func__, key, qKey);
 
 	e = ldap_first_entry(ldap, result);
 	if (!e) {
 		debug(MODPREFIX "%s: got answer, but no first entry for %s", __func__, query);
 		ldap_msgfree(result);
-		ldap_unbind(ldap);
 		return CHE_MISSING;
 	}
 
@@ -559,7 +626,6 @@ static int lookup_wild(const char *root,
 	if (!values) {
 		debug(MODPREFIX "%s: no %s defined for %s", __func__, type, query);
 		ldap_msgfree(result);
-		ldap_unbind(ldap);
 		return CHE_MISSING;
 	}
 
@@ -587,15 +653,38 @@ static int lookup_wild(const char *root,
 	/* Clean up. */
 	ldap_value_free(values);
 	ldap_msgfree(result);
-	ldap_unbind(ldap);
 
 	return ret;
 }
 
+
+static int lookup_wild(LDAP *ldap, const char *root,
+		       struct lookup_context *ctxt)
+{
+	int ret, i;
+
+	if (ctxt->schema)
+		return lookup_wild_schema(ldap, root, ctxt->schema, ctxt);
+
+
+	for (i = 0; i < NR_SCHEMAS; i++) {
+		ret = lookup_wild_schema(ldap, root,
+					 &supported_schemas[i], ctxt);
+		if (ret != CHE_FAIL) {
+			set_schema(ctxt, &supported_schemas[i]);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/* lookup_mount returns 1 if there was some kind of error */
 int lookup_mount(const char *root, const char *name, int name_len, void *context)
 {
 	struct lookup_context *ctxt = (struct lookup_context *) context;
-	int ret, ret2;
+	LDAP *ldap;
+	int ret;
 	char key[KEY_MAX_LEN + 1];
 	int key_len;
 	char mapent[MAPENT_MAX_LEN + 1];
@@ -613,42 +702,42 @@ int lookup_mount(const char *root, const char *name, int name_len, void *context
 	if (key_len > KEY_MAX_LEN)
 		return 1;
 
-	ret = lookup_one(root, key, "nisObject", "cn", "nisMapEntry", ctxt);
-	ret2 = lookup_one(root, key,
-			    "automount", "cn", "automountInformation", ctxt);
-	
-   	debug("ret = %d, ret2 = %d", ret, ret2);
 
-	if (!ret && !ret2)
+	/* Initialize the LDAP context. */
+	ldap = do_connect(ctxt, NULL);
+	if (!ldap)
+		return 0;
+	
+	ret = lookup_one(ldap, root, key, ctxt);
+	if (ret == CHE_FAIL) {
+		ldap_unbind(ldap);
 		return 1;
+	}
 
 	me = cache_lookup_first();
 	t_last_read = me ? now - me->age : ap.exp_runfreq + 1;
 
 	if (t_last_read > ap.exp_runfreq) 
-		if ((ret & (CHE_MISSING | CHE_UPDATED)) && 
-		    (ret2 & (CHE_MISSING | CHE_UPDATED)))
+		if (ret & (CHE_MISSING | CHE_UPDATED))
 			need_hup = 1;
 
-	if (ret == CHE_MISSING && ret2 == CHE_MISSING) {
+
+	if (ret == CHE_MISSING) {
 		int wild = CHE_MISSING;
 
 		/* Maybe update wild card map entry */
 		if (ap.type == LKP_INDIRECT) {
-			ret = lookup_wild(root, "nisObject",
-					  "cn", "nisMapEntry", ctxt);
-			ret2 = lookup_wild(root, "automount",
-					   "cn", "automountInformation", ctxt);
-			wild = (ret & (CHE_MISSING | CHE_FAIL)) &&
-					(ret2 & (CHE_MISSING | CHE_FAIL));
-
-			if (ret & CHE_MISSING && ret2 & CHE_MISSING)
+			ret = lookup_wild(ldap, root, ctxt);
+			wild = (ret & (CHE_MISSING | CHE_FAIL));
+
+			if (ret & CHE_MISSING)
 				cache_delete(root, "*", 0);
 		}
 
 		if (cache_delete(root, key, 0) && wild)
 			rmdir_path(key);
 	}
+	ldap_unbind(ldap);
 
 	me = cache_lookup(key);
 	if (me) {
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 5/8] Added option to ignore some highly unlikely paths before forking daemon
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
                   ` (3 preceding siblings ...)
  2010-12-20 19:30 ` [bryder_autofs_4.1.4_PATCH 4/8] reinstated the jmoyer ldap-cleanup patch and included man etc updates Bill Ryder
@ 2011-01-10  1:27 ` Bill Ryder
  2011-01-12  2:44 ` [bryder_autofs_4.1.4_PATCH 6/8] Adds options to retry nfs mounts on certain nfs errors Bill Ryder
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2011-01-10  1:27 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG           |   35 +++++++++++++++++++++++++++++++++++
 daemon/automount.c  |   51 ++++++++++++++++++++++++++++++++++++++++++++++++---
 include/automount.h |    5 +++++
 man/automount.8     |   10 ++++++++++
 4 files changed, 98 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 04043c5..9b0a418 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,38 @@
+01/07/2010 autofs-4.1.4 - bryder p41
+---------------------------
+ Adds the -I or --ignore-stupid-paths option.
+ 
+ The kernel nicely formats the path to mount up so that there are no extraneous dots or anything in it.
+ And it's just the part relative to the top level automount that gets passed to the daemon.
+ 
+ The -I option makes the automount daemon  return a fail to the kernel for any path with a '*' in it or 
+ if the path begins with a dot or if the path matches 'automount(pid'. 
+
+ It does this before it forks so it's very fast.
+
+ The odds are very good that no legimate path will be ignored. It's definitely true for my case but
+ YMMV.
+
+ The '*' paths are bad when you use ldap because it will match a lot of mount 
+ points and the first entry returned by the ldap search will be mounted  as /toplevelthing/*. 
+ 
+ The .blahblah paths are excluded because when serving NFS out to OSX and Windows via SAMBA 
+ we've found that OSX in particular will try to open a .directoryname for every directoryname 
+ in a mountpoint when browsing. This can be slow  when ghosting is on and you have a lot of 
+ mount points. Using this option it takes 0.001s more or less  to return a fail, without 
+ it it takes around 0.04s on the machine I tested. Mainly because the autmounter  forks before 
+ looking up the path. So 140 directories will delay you around 6s when a finder 
+ visits that top level automounter with that many entries. The 5.x automounter daemon doesn't fork so 
+ this is no such a big problem.
+
+ The 'automount(pid' path was added because samba will look for this path when it tries to get 
+ quotas on mount points.  I know I should fix samba but for now I'm adding it to the hacks 
+ I've already done for stupid paths. 
+
+ Ideally the automounter would have a list of regexes to ignore passed by command line option or config file 
+ but this patch hardcodes them.
+
+ 
 29/06/2010 autofs-4.1.4-p40
 ---------------------------
   Reinstates the jmoyer ldap-cleanup.patch from 4.1.3 which does cleaner LDAP schema handling. 
diff --git a/daemon/automount.c b/daemon/automount.c
index 0ef9cbb..2509431 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1013,6 +1013,34 @@ static int get_pkt(int fd, union autofs_packet_union *pkt)
 	}
 }
 
+static int is_path_stupid(const char *name)
+{ 
+	/* Returns 1 if the path contains a '*' or starts with a '.' */
+	if (strchr(name,'*')){ /* Any * in the ldap search will match - at least for our servers - DO NOT WANT! */
+		debug("%s: path: %s matches '*' - ignoring it",
+		      __func__,name);
+		return(1);
+	}
+	else if (name[0] == '.'){
+		debug("%s: path: %s starts with a dot (.)  - ignoring it",
+		      __func__,name);
+		return(1);
+	}
+	else if (strstr(name,"automount(pid")){
+		/* Samba has a habit of trying to mount up /mp/automount(pidNNNNN) - which of course fails */
+		/* It does this because it sees autmount(pidNNNN) /mp autofs etc etc in /etc/mtab and tries to get quota info for it */
+		/* I know I should fix samba but this is easier  for now */
+		debug("%s: path: %s contains 'automount(pid' - ignoring it",
+		      __func__,name);
+		return(1);
+
+		
+	}
+	else {
+		return(0);
+	}
+}
+
 static int handle_packet_missing(const struct autofs_packet_missing *pkt)
 {
 	struct stat st;
@@ -1020,8 +1048,8 @@ static int handle_packet_missing(const struct autofs_packet_missing *pkt)
 	pid_t f;
 	struct pending_mount *mt = NULL;
 
-	debug("handle_packet_missing: token %ld, name %s\n",
-		(unsigned long) pkt->wait_queue_token, pkt->name);
+	debug("handle_packet_missing: token %ld, mp %s name %s\n",
+	      (unsigned long) pkt->wait_queue_token, ap.path, pkt->name);
 
 	/* Ignore packet if we're trying to shut down */
 	if (ap.state == ST_SHUTDOWN_PENDING || ap.state == ST_SHUTDOWN) {
@@ -1029,6 +1057,18 @@ static int handle_packet_missing(const struct autofs_packet_missing *pkt)
 		return 0;
 	}
 
+	/* 
+	   Optionally ignore stupid path names.
+	   This will prevent silly ldap lookups like '*' which will mount up the first
+	   thing found. And MACS and PC's love .something directories. We NEVER create at the automount level these 
+	   and they waste time as automounter forks just to find out the path doesn't exist.
+	*/
+
+	if (ap.ignore_stupid_paths && is_path_stupid(pkt->name) ){
+		send_fail(pkt->wait_queue_token);
+		return 1;
+	}
+
 	chdir(ap.path);
 	if (lstat(pkt->name, &st) == -1 ||
 	   (S_ISDIR(st.st_mode) && st.st_dev == ap.dev)) {
@@ -1383,6 +1423,7 @@ static void usage(void)
 	fprintf(stderr, "Usage: %s [options] path map_type [args...]\n", program);
 	fprintf(stderr, "   -D|--dumpmap dumps out the maps read and exits\n");
 	fprintf(stderr, "   -u|--use-old-ldap-lookup instead of figuring out the schema once do it every single time a mount is requested. This is the old behaviour\n");
+ 	fprintf(stderr, "   -I|--ignore-stupid-paths will never lookup a requested path which contains the * character or which starts with a dot (.) \n");
 }
 
 static void setup_signals(__sighandler_t event_handler, __sighandler_t cld_handler)
@@ -1676,6 +1717,7 @@ int main(int argc, char *argv[])
 		{"submount", 0, &submount, 1},
 		{"dumpmap", 0, 0, 'D'},
 		{"use-old-ldap-lookup", 0, 0, 'u'},
+		{"ignore-stupid-paths", 0, 0, 'I'},
 		{0, 0, 0, 0}
 	};
 
@@ -1688,7 +1730,7 @@ int main(int argc, char *argv[])
 	ap.dir_created = 0; /* We haven't created the main directory yet */
 
 	opterr = 0;
-	while ((opt = getopt_long(argc, argv, "+hp:t:vdVgDu", long_options, NULL)) != EOF) {
+	while ((opt = getopt_long(argc, argv, "+hp:t:vdVgDuI", long_options, NULL)) != EOF) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -1724,6 +1766,9 @@ int main(int argc, char *argv[])
 		case 'u':
 			ap.use_old_ldap_lookup = 1;
 			break;
+		case 'I':
+			ap.ignore_stupid_paths = 1;
+			break;
 		case '?':
 		case ':':
 			printf("%s: Ambiguous or unknown options\n", program);
diff --git a/include/automount.h b/include/automount.h
index fa97764..46bc504 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -114,6 +114,11 @@ struct autofs_point {
 	unsigned dir_created;		/* Was a directory created for this
 					   mount? */
 	unsigned use_old_ldap_lookup;   /* query all schemas every time instead of sticking with the first one found */
+	unsigned ignore_stupid_paths;   /* Ignores mount keys that will never occur at my site and which slow
+                                         * everything down or lead to 'interesting' results 
+					 * See automount.c:is_path_stupid for details
+					 */
+ 
 };
 
 extern struct autofs_point ap; 
diff --git a/man/automount.8 b/man/automount.8
index 5dc597b..d242f58 100644
--- a/man/automount.8
+++ b/man/automount.8
@@ -54,6 +54,16 @@ the original rfc2307 schema. It only checks once for each mount point
 and remembers the schema for the rest of the automount invocation.
 If you set this flag it will do it the old way which involves looking
 for the schema every time a mount is requested.
+.TP
+.I "\-I, \-\-ignore\-stupid\-paths"
+The automounter will return 'not found' for any key which contains '*' or
+starts with a dot. Ignoring '*' stops undefined results being returned when
+you use ldap. Ignoring the leading '.' is
+useful for macs and Windows when they look for metadata directories
+which typically do not exist in the root of an automount tree to help
+increase browse speed at the top of large trees of mount points.
+It will also ignore paths containing 'autmount(pid'. This is to stop
+lookups when samba asks for these paths which do not exist of course.
 .SH ARGUMENTS
 \fBautomount\fP takes at least three arguments.  Mandatory arguments 
 include \fImount-point\fP, \fImap-type\fP, and \fImap\fP.  Both mandatory
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 6/8] Adds options to retry nfs mounts on certain nfs errors
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
                   ` (4 preceding siblings ...)
  2011-01-10  1:27 ` [bryder_autofs_4.1.4_PATCH 5/8] Added option to ignore some highly unlikely paths before forking daemon Bill Ryder
@ 2011-01-12  2:44 ` Bill Ryder
  2011-01-12 22:15 ` [bryder_autofs_4.1.4_PATCH 7/8] Ian Kent's reentrant syslog patch Bill Ryder
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2011-01-12  2:44 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG           |   32 ++++++++++++++++
 daemon/automount.c  |   21 +++++++++--
 daemon/spawn.c      |   64 +++++++++++++++++++++++++++++++-
 include/automount.h |    7 ++++
 man/automount.8     |   45 +++++++++++++++++++++++
 modules/mount_nfs.c |  100 ++++++++++++++++++++++++++++++++++++++-------------
 6 files changed, 239 insertions(+), 30 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 9b0a418..bbf4d3d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,35 @@
+14/07/2010 autofs-4.1.4 - bryder p42
+------------------------------------
+ Adds retrying to nfs mounts. 
+
+ Originally written to handle overloaded fileservers which is common
+ for us.   It's better for us if the automounter takes a long time to
+ mount a mount point than to return a 'not found' error just because
+ the fileserver was too busy to respond in a small amount of time. 
+
+ As a convenience (so we don't have to use the 'insecure' option on
+ the NFS server) it  also retries if the number of local secure ports
+ is exhausted. Some  jobs we run will mount up 100 fileservers at once
+ which will usually  trigger this error. It is a transient error so
+ the retry succeeds.
+
+ It works by reading the error returned from mount. Some of
+ these errors may be actual permanent failures so it will take longer
+ before it fails. Use the options to control the retries.
+ 
+   "RPC: Remote system error - Connection refused", /* heavy fileserver load */
+   "RPC: Timed out", /* heavy fileserver load */
+   "RPC: Remote system error - Connection timed out", /* heavy fileserver load */
+   "Input/output error", /* too many mounts starting at once on a client  - centos 2.6.18 */
+   "can't read superblock", /* too many mounts starting at once on a client - 2.6.25.18 and others */ 
+   "nfs bindresvport: Address already in use", /* too many mounts starting at once  - see in ubuntu 7.04 2.6.25.18 */
+   "mount system call failed",  /* too many mounts starting at once on a client - seen in 2.6.31.12 */
+   "server down",  /* Seen on ubuntu 7 with massive overload on a test fileserver  */
+
+ The options are --max-nfs-mount-retries|-R  and --nfs-mount-retry-pause|-P options
+ 
+ The pause is chosen at random between 1 second and the retry-pause amount + 1
+
 01/07/2010 autofs-4.1.4 - bryder p41
 ---------------------------
  Adds the -I or --ignore-stupid-paths option.
diff --git a/daemon/automount.c b/daemon/automount.c
index 2509431..3567abf 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1424,6 +1424,7 @@ static void usage(void)
 	fprintf(stderr, "   -D|--dumpmap dumps out the maps read and exits\n");
 	fprintf(stderr, "   -u|--use-old-ldap-lookup instead of figuring out the schema once do it every single time a mount is requested. This is the old behaviour\n");
  	fprintf(stderr, "   -I|--ignore-stupid-paths will never lookup a requested path which contains the * character or which starts with a dot (.) \n");
+ 	fprintf(stderr, "   -R|--max-nfs-mount-retries <n> and -P|--nfs-mount-retry-pause <max secs> retres nfs mounts when certain error messages are seen. Default is no retry. pause is max seconds to wait (the pause is random from 1 to (pause+1) seconds\n");
 }
 
 static void setup_signals(__sighandler_t event_handler, __sighandler_t cld_handler)
@@ -1718,6 +1719,8 @@ int main(int argc, char *argv[])
 		{"dumpmap", 0, 0, 'D'},
 		{"use-old-ldap-lookup", 0, 0, 'u'},
 		{"ignore-stupid-paths", 0, 0, 'I'},
+		{"max-nfs-mount-retries", 1, 0, 'R'},
+		{"nfs-mount-retry-pause", 1, 0, 'P'}, /* This is in fact the maximum pause - 1s (ie the code will randomly sleep between 1 and retry-pause +1 seconds) */
 		{0, 0, 0, 0}
 	};
 
@@ -1730,8 +1733,8 @@ int main(int argc, char *argv[])
 	ap.dir_created = 0; /* We haven't created the main directory yet */
 
 	opterr = 0;
-	while ((opt = getopt_long(argc, argv, "+hp:t:vdVgDuI", long_options, NULL)) != EOF) {
-		switch (opt) {
+	while ((opt = getopt_long(argc, argv, "+hp:t:vdVgDuIR:P:", long_options, NULL)) != EOF) {
+	  switch (opt) {
 		case 'h':
 			usage();
 			exit(0);
@@ -1769,13 +1772,25 @@ int main(int argc, char *argv[])
 		case 'I':
 			ap.ignore_stupid_paths = 1;
 			break;
+
+		case 'R':
+			ap.max_nfs_mount_retries =  getnumopt(optarg, opt);
+			break;
+
+		case 'P':
+			ap.nfs_mount_retry_pause =  getnumopt(optarg, opt);
+			break;
+
 		case '?':
 		case ':':
 			printf("%s: Ambiguous or unknown options\n", program);
 			exit(1);
 		}
 	}
-
+	/* Set this to a sane value even if it isn't used */
+	if (ap.nfs_mount_retry_pause <= 0){
+		ap.nfs_mount_retry_pause = 1;
+	}
 	if (geteuid() != 0) {
 		fprintf(stderr, "%s: This program must be run by root.\n", program);
 		exit(1);
diff --git a/daemon/spawn.c b/daemon/spawn.c
index f763cc7..12b3d5a 100644
--- a/daemon/spawn.c
+++ b/daemon/spawn.c
@@ -199,6 +199,60 @@ out:
 
 #define ERRBUFSIZ 2047		/* Max length of error string excl \0 */
 
+/*
+ * this is horrible. I need to evaluate the error from a failed mount request
+ * to see if it's a retryably NFS error
+ * But spawnv is called by spawn_mount and it's the only place that deals with the 
+ * error string that was returned by mount.
+ *
+ * the smallest change therefore is to run any error messages through retry_error_p and set a 
+ * gasp flag that says an error was returned that was retryable.
+ *
+ * This means I actually have nfs code in spawn.c which will never get past any maintainer because it 
+ * breaks the whole idea of separate modules.
+ *
+ * However - this approach won't break anything that doesn't use it and I won't have to introduce new argumenst
+ * and propogate them everywhere.
+ *
+ * how embarrassing.
+ */
+
+int found_retryable_error = 0  ; /* This is the variable we set. - it is defined as extern (obviously) in mount_nfs.c */
+
+
+/* These are the errors that can occur on a overloaded or if too many mounts are started up at once on a client */
+/* It's a substring match */
+static char *retryable_errors[] = {
+	"RPC: Remote system error - Connection refused", /* heavy fileserver load */
+	"RPC: Timed out", /* heavy fileserver load */
+	"RPC: Remote system error - Connection timed out", /* heavy fileserver load */
+	"Input/output error", /* too many mounts starting at once on a client  - centos 2.6.18 */
+	"can't read superblock", /* too many mounts starting at once on a client - 2.6.25.18 and others */ 
+	"nfs bindresvport: Address already in use", /* too many mounts starting at once  - see in ubuntu 7.04 2.6.25.18 */
+	"mount system call failed",  /* too many mounts starting at once on a client - seen in 2.6.31.12 */
+	"server is down",  /* Massively overloaded fileserver - seen on kubuntu 7 */
+};
+
+
+/*
+ * retry_error_p returns a string which the error message matched if that error is retryable.
+ * if it returns NULL then the error is not retryable. 
+ */
+char *retry_error_p(char *error_mesg) /* _p means predicate - is it's a test - old LISP  naming */
+{ /* retry_error_p */
+	int i;
+	
+	for (i = 0; i < (sizeof(retryable_errors)/sizeof(char *)) ; i++){
+		if (strstr(error_mesg,retryable_errors[i]) != NULL){
+			debug("spawn.c:%s: Found a retryable error %s", __func__, retryable_errors[i]) ;
+			return(retryable_errors[i]);
+		}
+	}
+
+	return NULL;
+	  
+} /* retry_error_p */
+
 static int do_spawn(int logpri, int use_lock, const char *prog, const char *const *argv)
 {
 	pid_t f;
@@ -247,6 +301,8 @@ static int do_spawn(int logpri, int use_lock, const char *prog, const char *cons
 			return -1;
 		}
 
+		found_retryable_error = 0;
+
 		errp = 0;
 		do {
 			while ((errn =
@@ -257,10 +313,14 @@ static int do_spawn(int logpri, int use_lock, const char *prog, const char *cons
 				errp += errn;
 
 				sp = errbuf;
+
+				if((ap.max_nfs_mount_retries > 0) &&  retry_error_p(errbuf))
+				   found_retryable_error = 1 ;
+
 				while (errp && (p = memchr(sp, '\n', errp))) {
 					*p++ = '\0';
 					if (sp[0])	/* Don't output empty lines */
-						syslog(logpri, ">> %s", sp);
+					  syslog(logpri, "%s 1 >> %s", __func__, sp);
 					errp -= (p - sp);
 					sp = p;
 				}
@@ -271,7 +331,7 @@ static int do_spawn(int logpri, int use_lock, const char *prog, const char *cons
 				if (errp >= ERRBUFSIZ) {
 					/* Line too long, split */
 					errbuf[errp] = '\0';
-					syslog(logpri, ">> %s", errbuf);
+					syslog(logpri, "%s 2 >> %s", __func__, errbuf);
 					errp = 0;
 				}
 			}
diff --git a/include/automount.h b/include/automount.h
index 46bc504..b09dd78 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -119,6 +119,13 @@ struct autofs_point {
 					 * See automount.c:is_path_stupid for details
 					 */
  
+
+	unsigned max_nfs_mount_retries; /* number of times to retry a failed nfs mount if it 
+					 * returns specified error messages (see mount_nfs.c for the errors 
+					 */
+	unsigned nfs_mount_retry_pause; /* Time in seconds to pause between retrying nfs mounts */
+        
+
 };
 
 extern struct autofs_point ap; 
diff --git a/man/automount.8 b/man/automount.8
index d242f58..f96390b 100644
--- a/man/automount.8
+++ b/man/automount.8
@@ -64,6 +64,51 @@ which typically do not exist in the root of an automount tree to help
 increase browse speed at the top of large trees of mount points.
 It will also ignore paths containing 'autmount(pid'. This is to stop
 lookups when samba asks for these paths which do not exist of course.
+.TP
+.I "\-R, \-\-max\-nfs\-mount\-retries <n>"
+If set automount will retry 
+.B "n"
+times waiting between 1 and the argument to nfs-mount-retry-pause seconds
+(+1) between mounts 
+if one of the following errors is seen:
+.RS
+.P
+.I "RPC: Remote system error - Connection refused" 
+- usually caused by heavy fileserver load
+.P
+.I "RPC: Timed out"
+- usually caused by heavy fileserver load 
+.P
+.I "RPC: Remote system error - Connection timed out"
+ - usually caused by heavy fileserver load
+.P
+.I "Input/output error"
+- sometimes caused by  too many mounts starting at
+once on a client  - seen on centos 5.4 with kernel  2.6.18
+.P
+.I "can't read superblock"
+-  too many mounts starting at once on a client
+.P
+.I "nfs bindresvport: Address already in use"
+-  too many mounts starting at once
+.P
+.I "mount system call failed"
+- too many mounts starting at once on a client
+.P
+.I "server is down"
+-  Massively overloaded fileserve
+.P
+.I "nfs can't read superblock"
+-  too many mounts starting at once on a client
+.RE
+.TP
+.I "\-R, \-\-nfs\-mount\-retry\-pause <secs>"
+The amount of time to pause between retries. In fact it sets the
+upperbound on the number of seconds before retrying (1s is added to
+this argument). So it will pause a random number of seconds between 1
+and nfs-mount-retry-pause+1 between retries.
+
+
 .SH ARGUMENTS
 \fBautomount\fP takes at least three arguments.  Mandatory arguments 
 include \fImount-point\fP, \fImap-type\fP, and \fImap\fP.  Both mandatory
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index 998c5ba..a3135de 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -310,6 +310,19 @@ int get_best_mount(char *what, const char *original, int longtimeout, int skiplo
 	return local;
 }
 
+/*
+ * Note - I've done a hideous hack to spawn.c to handle retryable errors in the mount
+ *
+ * unfortunately the error message is not propagated back to the mount_mount from the spwan_mount.
+ *
+ *  But to decide if a retry is necessary the error message has to be examined.
+ *
+ *  The hack involves checking the error message in spawn.c:spawnv and propagating the result
+ *  via the following variable:
+ */
+extern int found_retryable_error;
+
+
 int mount_mount(const char *root, const char *name, int name_len,
 		const char *what, const char *fstype, const char *options,
 		void *context)
@@ -320,6 +333,7 @@ int mount_mount(const char *root, const char *name, int name_len,
 	int local, err;
 	int nosymlink = 0;
 	int ro = 0;            /* Set if mount bind should be read-only */
+	int mount_attempts = 0; 
 
 	debug(MODPREFIX "root=%s name=%s what=%s, fstype=%s, options=%s",
 	      root, name, what, fstype, options);
@@ -445,33 +459,69 @@ int mount_mount(const char *root, const char *name, int name_len,
 			return 0;
 		}
 
-		if (nfsoptions && *nfsoptions) {
-			debug(MODPREFIX "calling mount -t nfs " SLOPPY 
-			      " -o %s %s %s", nfsoptions, whatstr, fullpath);
-
-			err = spawnll(LOG_NOTICE,
-				     PATH_MOUNT, PATH_MOUNT, "-t",
-				     "nfs", SLOPPYOPT "-o", nfsoptions,
-				     whatstr, fullpath, NULL);
-		} else {
-			debug(MODPREFIX "calling mount -t nfs %s %s",
-			      whatstr, fullpath);
-			err = spawnll(LOG_NOTICE,
-				     PATH_MOUNT, PATH_MOUNT, "-t",
-				     "nfs", whatstr, fullpath, NULL);
-		}
+		/*  Retry the mount if the error is retryable and the max_nfs-mount_retries > 0 . */
+		mount_attempts = 0;
 
-		if (err) {
-			if ((!ap.ghost && name_len) || !existed)
-				rmdir_path(name);
+		do {
+			if (nfsoptions && *nfsoptions) {
+				debug(MODPREFIX "calling mount -t nfs " SLOPPY 
+				      " -o %s %s %s", nfsoptions, whatstr, fullpath);
 
-			error(MODPREFIX "nfs: mount failure %s on %s",
-			      whatstr, fullpath);
-			return 1;
-		} else {
-			debug(MODPREFIX "mounted %s on %s", whatstr, fullpath);
-			return 0;
-		}
+				err = spawnll(LOG_NOTICE,
+					      PATH_MOUNT, PATH_MOUNT, "-t",
+					      "nfs", SLOPPYOPT "-o", nfsoptions,
+					      whatstr, fullpath, NULL);
+			} else {
+				debug(MODPREFIX "calling mount -t nfs %s %s",
+				      whatstr, fullpath);
+				err = spawnll(LOG_NOTICE,
+					      PATH_MOUNT, PATH_MOUNT, "-t",
+					      "nfs", whatstr, fullpath, NULL);
+			}
+			mount_attempts++;
+			if (err) {
+
+				/*
+				 * found_retryable_error is set in spawn.c - I kid you not. It's the least invasive hack bryder could make 
+				 * since the error message from a failed mount is not passed back. 
+				 * The flag is true of one of a set of retryable error messages were seen.
+				 */
+				if (found_retryable_error && (mount_attempts <= ap.max_nfs_mount_retries)){
+					error(MODPREFIX "nfs: mount failure %s on %s - trying %d more times", whatstr, fullpath, (ap.max_nfs_mount_retries - mount_attempts)+1);
+					if (ap.nfs_mount_retry_pause > 0 ){
+						int fd = open("/dev/urandom", O_RDONLY);
+						if (fd < 0) {
+							srand(time(NULL));
+						} 
+						else  {
+							unsigned int seed;
+							read(fd, &seed, sizeof(seed));
+							srand(seed);
+							close(fd);
+						}
+
+						/* Randomise the sleep time  - between 1s and the max (+1s)*/
+						useconds_t sleep_usecs = 1000000 + (int)(((float)ap.nfs_mount_retry_pause * 1000000 ) * (((float)rand() / (float)RAND_MAX)));
+						debug(MODPREFIX "nfs: mount failed - sleeping %d microsecs before retry",(unsigned int)sleep_usecs); 
+						usleep(sleep_usecs);
+					}
+					continue; 
+				} else {
+					if ((!ap.ghost && name_len) || !existed)
+						rmdir_path(name);
+
+					error(MODPREFIX "nfs: mount failure %s on %s",
+					      whatstr, fullpath);
+					return 1;
+				}
+			} else {
+				break; /* good mount - get out of the loop and return */
+			}
+		} while (mount_attempts <= ap.max_nfs_mount_retries ); /* loop is also exited via a couple of breaks  and returns */
+
+			
+		debug(MODPREFIX "%s: mounted %s on %s after %d attempts", __func__, whatstr, fullpath, mount_attempts );
+		return 0;
 	}
 }
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 7/8] Ian Kent's reentrant syslog patch
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
                   ` (5 preceding siblings ...)
  2011-01-12  2:44 ` [bryder_autofs_4.1.4_PATCH 6/8] Adds options to retry nfs mounts on certain nfs errors Bill Ryder
@ 2011-01-12 22:15 ` Bill Ryder
  2011-01-27 14:33   ` Ian Kent
  2011-01-12 22:25 ` [bryder_autofs_4.1.4_PATCH 8/8] Fix race which would stop a daemon under high mount rates with failures Bill Ryder
  2011-01-26  0:17 ` [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
  8 siblings, 1 reply; 11+ messages in thread
From: Bill Ryder @ 2011-01-12 22:15 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG           |    8 +
 COPYRIGHT           |   36 +++-
 daemon/automount.c  |   72 +++++--
 include/automount.h |   27 +++
 include/syslog.h    |  201 +++++++++++++++++
 lib/Makefile        |    5 +-
 lib/syslog.c        |  383 +++++++++++++++++++++++++++++++
 lib/vsprintf.c      |  619 +++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 1332 insertions(+), 19 deletions(-)
 create mode 100644 include/syslog.h
 create mode 100644 lib/syslog.c
 create mode 100644 lib/vsprintf.c

diff --git a/CHANGELOG b/CHANGELOG
index bbf4d3d..b4959ec 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,11 @@
+15/07/2010 autofs-4.1.4 - syslog patch
+--------------------------------------
+
+This patch is necessary - especially when using debug syslog messages
+and testing high mount rates. Without it I've see the daemon wedge in
+syslog. I'm pretty sure Ian Kent did the patch.
+
+
 14/07/2010 autofs-4.1.4 - bryder p42
 ------------------------------------
  Adds retrying to nfs mounts. 
diff --git a/COPYRIGHT b/COPYRIGHT
index cf647f8..ee56c0c 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -14,4 +14,38 @@ For all software in this distribution unless otherwise indicated:
    GNU General Public License for more details.
 
 Portions Copyright (C) 1999-2000 Jeremy Fitzhardinge
-Portions Copyright (C) 2001-2003 Ian Kent
+Portions Copyright (C) 2001-2005 Ian Kent
+
+The files lib/syslog.c and include/syslog.h are licenced under the
+BSD License and require that a copy of the notice ibelow be included in
+accompanying documentation and be distributed with binary distributions
+of the code, so be sure to include this file along with any binary
+distributions derived from this source package.
+
+Copyright (c) 1983, 1988, 1993
+     The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
diff --git a/daemon/automount.c b/daemon/automount.c
index 3567abf..92476b4 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -38,13 +38,32 @@
 #include <sys/poll.h>
 #include <linux/auto_fs4.h>
 
+#include "automount.h"
+
 #ifndef NDEBUG
-#define assert(x)	do { if (!(x)) { syslog(LOG_CRIT, __FILE__ ":%d: assertion failed: " #x, __LINE__); } } while(0)
+#define assert(x) 						    \
+	do { 							    \
+		if (!(x)) {					    \
+			crit(__FILE__ ":%d: assertion failed: " #x, \
+				__LINE__);			    \
+		}						    \
+	} while(0)
 #else
 #define assert(x)	do { } while(0)
 #endif
 
-#include "automount.h"
+#ifndef NDEBUG
+#define assert_r(context, x) 					   \
+	do { 							   \
+		if (!(x)) {					   \
+			crit_r(context,				   \
+				__FILE__ ":%d: assertion failed: ",\
+				__LINE__);			   \
+		}						   \
+	} while(0)
+#else
+#define assert_r(context, x)	do { } while(0)
+#endif
 
 const char *program;		/* Initialized with argv[0] */
 const char *version = VERSION_STRING;	/* Program version */
@@ -68,6 +87,9 @@ sigset_t sigchld_mask;
 
 struct autofs_point ap;
 
+/* re-entrant syslog default context data */
+#define AUTOFS_SYSLOG_CONTEXT {-1, 0, 0, LOG_PID, (const char *)0, LOG_DAEMON, 0xff}
+
 volatile struct pending_mount *junk_mounts = NULL;
 
 #define CHECK_RATIO     4	/* exp_runfreq = exp_timeout/CHECK_RATIO */
@@ -481,19 +503,25 @@ static int mount_autofs(char *path)
 
 static void nextstate(enum states next)
 {
+	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+	static struct syslog_data *slc = &syslog_context;
+
 	if (write(ap.state_pipe[1], &next, sizeof(next)) != sizeof(next))
-		error("nextstate: write failed %m");
+		error_r(slc, "nextstate: write failed %m");
 }
 
 /* Deal with all the signal-driven events in the state machine */
 static void sig_statemachine(int sig)
 {
+	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+	static struct syslog_data *slc = &syslog_context;
 	int save_errno = errno;
 	enum states next = ap.state;
 
 	switch (sig) {
 	default:		/* all the "can't happen" signals */
-		error("process %d got unexpected signal %d!", getpid(), sig);
+		error_r(slc, "process %d got unexpected signal %d!",
+			getpid(), sig);
 		break;
 		/* don't FALLTHROUGH */
 
@@ -519,18 +547,21 @@ static void sig_statemachine(int sig)
 		break;
 	}
 
-	debug("sig %d switching from %d to %d", sig, ap.state, next);
+	debug_r(slc, "sig %d switching from %d to %d", sig, ap.state, next);
 
 	errno = save_errno;
 }
 
 static int send_ready(unsigned int wait_queue_token)
 {
+	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+	static struct syslog_data *slc = &syslog_context;
+
 	if (wait_queue_token == 0)
 		return 0;
-	debug("send_ready: token=%d\n", wait_queue_token);
+	debug_r(slc, "send_ready: token=%d\n", wait_queue_token);
 	if (ioctl(ap.ioctlfd, AUTOFS_IOC_READY, wait_queue_token) < 0) {
-		error("AUTOFS_IOC_READY: %m");
+		error_r(slc, "AUTOFS_IOC_READY: %m");
 		return 1;
 	}
 	return 0;
@@ -538,11 +569,14 @@ static int send_ready(unsigned int wait_queue_token)
 
 static int send_fail(unsigned int wait_queue_token)
 {
+	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+	static struct syslog_data *slc = &syslog_context;
+
 	if (wait_queue_token == 0)
 		return 0;
-	debug("send_fail: token=%d\n", wait_queue_token);
+	debug_r(slc, "send_fail: token=%d\n", wait_queue_token);
 	if (ioctl(ap.ioctlfd, AUTOFS_IOC_FAIL, wait_queue_token) < 0) {
-		syslog(LOG_ERR, "AUTOFS_IOC_FAIL: %m");
+		error_r(slc, "AUTOFS_IOC_FAIL: %m");
 		return 1;
 	}
 	return 0;
@@ -553,6 +587,8 @@ static int send_fail(unsigned int wait_queue_token)
    result.  */
 static enum states handle_child(int hang)
 {
+	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+	static struct syslog_data *slc = &syslog_context;
 	pid_t pid;
 	int status;
 	enum states next = ST_INVAL;
@@ -560,7 +596,7 @@ static enum states handle_child(int hang)
 	while ((pid = waitpid(-1, &status, hang ? 0 : WNOHANG)) > 0) {
 		struct pending_mount volatile *mt, *volatile *mtp;
 
-		debug("handle_child: got pid %d, sig %d (%d), stat %d\n",
+		debug_r(slc, "handle_child: got pid %d, sig %d (%d), stat %d",
 			pid, WIFSIGNALED(status),
 			WTERMSIG(status), WEXITSTATUS(status));
 
@@ -606,18 +642,19 @@ static enum states handle_child(int hang)
 				}
 
 				/* Failed shutdown returns to ready */
-				warn("can't shutdown: filesystem %s still busy",
-				     ap.path);
+				warn_r(slc,
+				   "can't shutdown: filesystem %s still busy",
+				   ap.path);
 				alarm(ap.exp_runfreq);
 				next = ST_READY;
 				break;
 
 			default:
-				error("bad state %d", ap.state);
+				error_r(slc, "bad state %d", ap.state);
 			}
 
 			if (next != ST_INVAL)
-				debug("sigchld: exp "
+				debug_r(slc, "sigchld: exp "
 				     "%d finished, switching from %d to %d",
 				     pid, ap.state, next);
 
@@ -633,7 +670,7 @@ static enum states handle_child(int hang)
 			if (!WIFEXITED(status) && !WIFSIGNALED(status))
 				break;
 
-			debug("sig_child: found pending iop pid %d: "
+			debug_r(slc, "sig_child: found pending iop pid %d: "
 			     "signalled %d (sig %d), exit status %d",
 				pid, WIFSIGNALED(status),
 				WTERMSIG(status), WEXITSTATUS(status));
@@ -1530,11 +1567,14 @@ static void setup_signals(__sighandler_t event_handler, __sighandler_t cld_handl
 /* Deal with the signals recieved by direct mount supervisor */
 static void sig_supervisor(int sig)
 {
+	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+	static struct syslog_data *slc = &syslog_context;
 	int save_errno = errno;
 
 	switch (sig) {
 	default:		/* all the signals not handled */
-		error("process %d got unexpected signal %d!", getpid(), sig);
+		error_r(slc, "process %d got unexpected signal %d!",
+			getpid(), sig);
 		return;
 		/* don't FALLTHROUGH */
 
diff --git a/include/automount.h b/include/automount.h
index b09dd78..72f6c91 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -15,6 +15,9 @@
 #include <time.h>
 #include "config.h"
 
+/* OpenBSD re-entrant syslog */
+#include "syslog.h"
+
 /* We MUST have the paths to mount(8) and umount(8) */
 #ifndef HAVE_MOUNT
 #error Failed to locate mount(8)!
@@ -318,5 +321,29 @@ if (do_verbose || do_debug) 		\
 if (do_debug) 				\
 	syslog(LOG_DEBUG, msg, ##args);
 
+/* Define reentrant logging macros for signal handlers */
+
+#define debug_r(context, msg, args...)				\
+do {								\
+	if (do_debug)						\
+		syslog_r(LOG_DEBUG, context, msg, ##args);	\
+} while (0)
+
+#define warn_r(context, msg, args...)				\
+do {								\
+	if (do_verbose || do_debug)				\
+		syslog_r(LOG_WARNING, context, msg, ##args);	\
+} while (0)
+
+#define error_r(context, msg, args...)			\
+do {							\
+	syslog_r(LOG_ERR, context, msg, ##args);	\
+} while (0)
+
+#define crit_r(context, msg, args...)			\
+do {							\
+	syslog_r(LOG_CRIT, context, msg, ##args);	\
+} while (0)
+
 #endif
 
diff --git a/include/syslog.h b/include/syslog.h
new file mode 100644
index 0000000..9f1cae4
--- /dev/null
+++ b/include/syslog.h
@@ -0,0 +1,201 @@
+/*	$OpenBSD: syslog.h,v 1.11 2003/08/24 01:27:07 avsm Exp $	*/
+/*	$NetBSD: syslog.h,v 1.14 1996/04/03 20:46:44 christos Exp $	*/
+
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)syslog.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _SYS_SYSLOG_H_
+#define _SYS_SYSLOG_H_
+
+#include <features.h>
+#define __need___va_list
+#include <stdarg.h>
+
+#define	_PATH_LOG	"/dev/log"
+
+/*
+ * priorities/facilities are encoded into a single 32-bit quantity, where the
+ * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
+ * (0-big number).  Both the priorities and the facilities map roughly
+ * one-to-one to strings in the syslogd(8) source code.  This mapping is
+ * included in this file.
+ *
+ * priorities (these are ordered)
+ */
+#define	LOG_EMERG	0	/* system is unusable */
+#define	LOG_ALERT	1	/* action must be taken immediately */
+#define	LOG_CRIT	2	/* critical conditions */
+#define	LOG_ERR		3	/* error conditions */
+#define	LOG_WARNING	4	/* warning conditions */
+#define	LOG_NOTICE	5	/* normal but significant condition */
+#define	LOG_INFO	6	/* informational */
+#define	LOG_DEBUG	7	/* debug-level messages */
+
+#define	LOG_PRIMASK	0x07	/* mask to extract priority part (internal) */
+				/* extract priority */
+#define	LOG_PRI(p)	((p) & LOG_PRIMASK)
+#define	LOG_MAKEPRI(fac, pri)	(((fac) << 3) | (pri))
+
+#ifdef SYSLOG_NAMES
+#define	INTERNAL_NOPRI	0x10	/* the "no priority" priority */
+				/* mark "facility" */
+#define	INTERNAL_MARK	LOG_MAKEPRI(LOG_NFACILITIES, 0)
+typedef struct _code {
+	char	*c_name;
+	int	c_val;
+} CODE;
+
+CODE prioritynames[] = {
+	{ "alert",	LOG_ALERT },
+	{ "crit",	LOG_CRIT },
+	{ "debug",	LOG_DEBUG },
+	{ "emerg",	LOG_EMERG },
+	{ "err",	LOG_ERR },
+	{ "error",	LOG_ERR },		/* DEPRECATED */
+	{ "info",	LOG_INFO },
+	{ "none",	INTERNAL_NOPRI },	/* INTERNAL */
+	{ "notice",	LOG_NOTICE },
+	{ "panic", 	LOG_EMERG },		/* DEPRECATED */
+	{ "warn",	LOG_WARNING },		/* DEPRECATED */
+	{ "warning",	LOG_WARNING },
+	{ NULL,		-1 },
+};
+#endif
+
+/* facility codes */
+#define	LOG_KERN	(0<<3)	/* kernel messages */
+#define	LOG_USER	(1<<3)	/* random user-level messages */
+#define	LOG_MAIL	(2<<3)	/* mail system */
+#define	LOG_DAEMON	(3<<3)	/* system daemons */
+#define	LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define	LOG_SYSLOG	(5<<3)	/* messages generated internally by syslogd */
+#define	LOG_LPR		(6<<3)	/* line printer subsystem */
+#define	LOG_NEWS	(7<<3)	/* network news subsystem */
+#define	LOG_UUCP	(8<<3)	/* UUCP subsystem */
+#define	LOG_CRON	(9<<3)	/* clock daemon */
+#define	LOG_AUTHPRIV	(10<<3)	/* security/authorization messages (private) */
+#define	LOG_FTP		(11<<3)	/* ftp daemon */
+
+	/* other codes through 15 reserved for system use */
+#define	LOG_LOCAL0	(16<<3)	/* reserved for local use */
+#define	LOG_LOCAL1	(17<<3)	/* reserved for local use */
+#define	LOG_LOCAL2	(18<<3)	/* reserved for local use */
+#define	LOG_LOCAL3	(19<<3)	/* reserved for local use */
+#define	LOG_LOCAL4	(20<<3)	/* reserved for local use */
+#define	LOG_LOCAL5	(21<<3)	/* reserved for local use */
+#define	LOG_LOCAL6	(22<<3)	/* reserved for local use */
+#define	LOG_LOCAL7	(23<<3)	/* reserved for local use */
+
+#define	LOG_NFACILITIES	24	/* current number of facilities */
+#define	LOG_FACMASK	0x03f8	/* mask to extract facility part */
+				/* facility of pri */
+#define	LOG_FAC(p)	(((p) & LOG_FACMASK) >> 3)
+
+#ifdef SYSLOG_NAMES
+CODE facilitynames[] = {
+	{ "auth",	LOG_AUTH },
+	{ "authpriv",	LOG_AUTHPRIV },
+	{ "cron", 	LOG_CRON },
+	{ "daemon",	LOG_DAEMON },
+	{ "ftp",	LOG_FTP },
+	{ "kern",	LOG_KERN },
+	{ "lpr",	LOG_LPR },
+	{ "mail",	LOG_MAIL },
+	{ "mark", 	INTERNAL_MARK },	/* INTERNAL */
+	{ "news",	LOG_NEWS },
+	{ "security",	LOG_AUTH },		/* DEPRECATED */
+	{ "syslog",	LOG_SYSLOG },
+	{ "user",	LOG_USER },
+	{ "uucp",	LOG_UUCP },
+	{ "local0",	LOG_LOCAL0 },
+	{ "local1",	LOG_LOCAL1 },
+	{ "local2",	LOG_LOCAL2 },
+	{ "local3",	LOG_LOCAL3 },
+	{ "local4",	LOG_LOCAL4 },
+	{ "local5",	LOG_LOCAL5 },
+	{ "local6",	LOG_LOCAL6 },
+	{ "local7",	LOG_LOCAL7 },
+	{ NULL,		-1 },
+};
+#endif
+
+/* Used by reentrant functions */
+
+struct syslog_data {
+	int	log_file;
+	int	connected;
+	int	opened;
+	int	log_stat;
+	const char 	*log_tag;
+	int 	log_fac;
+	int 	log_mask;
+};
+
+#define SYSLOG_DATA_INIT {-1, 0, 0, 0, (const char *)0, LOG_USER, 0xff}
+
+/*
+ * arguments to setlogmask.
+ */
+#define	LOG_MASK(pri)	(1 << (pri))		/* mask for one priority */
+#define	LOG_UPTO(pri)	((1 << ((pri)+1)) - 1)	/* all priorities through pri */
+
+/*
+ * Option flags for openlog.
+ *
+ * LOG_ODELAY no longer does anything.
+ * LOG_NDELAY is the inverse of what it used to be.
+ */
+#define	LOG_PID		0x01	/* log the pid with each message */
+#define	LOG_CONS	0x02	/* log on the console if errors in sending */
+#define	LOG_ODELAY	0x04	/* delay open until first syslog() (default) */
+#define	LOG_NDELAY	0x08	/* don't delay open */
+#define	LOG_NOWAIT	0x10	/* don't wait for console forks: DEPRECATED */
+#define	LOG_PERROR	0x20	/* log to stderr as well */
+
+__BEGIN_DECLS
+void	closelog(void);
+void	openlog(const char *__ident, int __option, int __facility);
+int	setlogmask(int __mask);
+void	syslog(int __pri, const char *__fmt, ...)
+		__attribute__((__format__(__printf__, 2, 3)));
+void	vsyslog(int __pri, const char *, __gnuc_va_list __ap)
+		__attribute__((__format__(__printf__, 2, 0)));
+void	closelog_r(struct syslog_data *__data);
+void	openlog_r(const char *__ident, int __option, int __facility, struct syslog_data *__data);
+int	setlogmask_r(int __mask, struct syslog_data *__data);
+void	syslog_r(int __pri, struct syslog_data *__data, const char *__fmt, ...)
+		__attribute__((__format__(__printf__, 3, 4)));
+void	vsyslog_r(int __pri, struct syslog_data *__data, const char *__fmt, __gnuc_va_list __ap)
+		__attribute__((__format__(__printf__, 3, 0)));
+__END_DECLS
+
+#endif /* !_SYS_SYSLOG_H_ */
+
diff --git a/lib/Makefile b/lib/Makefile
index 5cc809c..1771b1f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,10 +9,11 @@ include ../Makefile.rules
 RPCGEN = /usr/bin/rpcgen
 RANLIB = /usr/bin/ranlib
 
-SRCS = cache.c listmount.c cat_path.c rpc_subs.c mounts.c lock.c
+SRCS = cache.c listmount.c cat_path.c rpc_subs.c mounts.c lock.c syslog.c \
+	vsprintf.c
 RPCS = mount.h mount_clnt.c mount_xdr.c
 OBJS = cache.o mount_clnt.o mount_xdr.o listmount.o \
-	cat_path.o rpc_subs.o mounts.o lock.o
+	cat_path.o rpc_subs.o mounts.o lock.o syslog.o vsprintf.o
 
 LIB = autofs.a
 
diff --git a/lib/syslog.c b/lib/syslog.c
new file mode 100644
index 0000000..9e5623e
--- /dev/null
+++ b/lib/syslog.c
@@ -0,0 +1,383 @@
+#ident "$Id: syslog.c,v 1.1 2005/05/01 09:48:34 raven Exp $"
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "syslog.h"
+
+#define	TBUF_LEN	2048
+#define	FMT_LEN		1024
+#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
+
+#define	DEC()					\
+	do {					\
+		if (prlen < 0)			\
+			prlen = 0;		\
+		if (prlen >= tbuf_left)		\
+			prlen = tbuf_left - 1;	\
+		p += prlen;			\
+		tbuf_left -= prlen;		\
+	} while (0)
+
+/* Use our internal printf routines */
+extern int snprintf_int(char * buf, size_t size, const char * fmt, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern int vsnprintf_int(char *buf, size_t size, const char *fmt, va_list args)
+	__attribute__ ((format (printf, 3, 0)));
+
+static struct syslog_data sdata = SYSLOG_DATA_INIT;
+static int LogType = SOCK_DGRAM;	/* type of socket connection */
+
+extern char	*__progname;		/* Program name, from crt0. */
+
+static void	disconnectlog_r(struct syslog_data *);	/* disconnect from syslogd */
+static void	connectlog_r(struct syslog_data *);	/* (re)connect to syslogd */
+
+/*
+ * syslog, vsyslog --
+ *	print message on log file; output is intended for syslogd(8).
+ */
+void
+syslog(int pri, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsyslog(pri, fmt, ap);
+	va_end(ap);
+}
+
+void
+vsyslog(int pri, const char *fmt, va_list ap)
+{
+	vsyslog_r(pri, &sdata, fmt, ap);
+}
+
+void
+openlog(const char *ident, int logstat, int logfac)
+{
+	openlog_r(ident, logstat, logfac, &sdata);
+}
+
+void
+closelog(void)
+{
+	closelog_r(&sdata);
+}
+
+/* setlogmask -- set the log mask level */
+int
+setlogmask(int pmask)
+{
+	return setlogmask_r(pmask, &sdata);
+}
+
+/* Reentrant version of syslog, i.e. syslog_r() */
+
+void
+syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsyslog_r(pri, data, fmt, ap);
+	va_end(ap);
+}
+
+void
+vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
+{
+	int cnt;
+	char ch, *p, *t;
+	time_t now;
+	int fd, saved_errno, error;
+	char *stdp = NULL, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
+	int tbuf_left, fmt_left, prlen;
+
+	/* Check for invalid bits. */
+	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
+		if (data == &sdata) {
+			syslog(INTERNALLOG,
+			    "syslog: unknown facility/priority: %x", pri);
+		} else {
+			syslog_r(INTERNALLOG, data,
+			    "syslog_r: unknown facility/priority: %x", pri);
+		}
+		pri &= LOG_PRIMASK|LOG_FACMASK;
+	}
+
+	/* Check priority against setlogmask values. */
+	if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
+		return;
+
+	saved_errno = errno;
+
+	/* Set default facility if none specified. */
+	if ((pri & LOG_FACMASK) == 0)
+		pri |= data->log_fac;
+
+	/* If we have been called through syslog(), no need for reentrancy. */
+	if (data == &sdata)
+		(void)time(&now);
+
+	p = tbuf;
+	tbuf_left = TBUF_LEN;
+
+	prlen = snprintf_int(p, tbuf_left, "<%d>", pri);
+	DEC();
+
+	/* 
+	 * syslogd will expand time automagically for reentrant case, and
+	 * for normal case, just do like before
+	 */
+	if (data == &sdata) {
+		prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now));
+		DEC();
+	}
+
+	if (data->log_stat & LOG_PERROR)
+		stdp = p;
+	if (data->log_tag == NULL)
+		data->log_tag = __progname;
+	if (data->log_tag != NULL) {
+		prlen = snprintf_int(p, tbuf_left, "%s", data->log_tag);
+		DEC();
+	}
+	if (data->log_stat & LOG_PID) {
+		prlen = snprintf_int(p, tbuf_left, "[%ld]", (long)getpid());
+		DEC();
+	}
+	if (data->log_tag != NULL) {
+		if (tbuf_left > 1) {
+			*p++ = ':';
+			tbuf_left--;
+		}
+		if (tbuf_left > 1) {
+			*p++ = ' ';
+			tbuf_left--;
+		}
+	}
+
+	/* strerror() is not reentrant */
+
+	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
+		if (ch == '%' && fmt[1] == 'm') {
+			++fmt;
+			if (data == &sdata) {
+				prlen = snprintf_int(t, fmt_left, "%s",
+				    strerror(saved_errno)); 
+			} else {
+				prlen = snprintf_int(t, fmt_left, "Error %d",
+				    saved_errno); 
+			}
+			if (prlen < 0)
+				prlen = 0;
+			if (prlen >= fmt_left)
+				prlen = fmt_left - 1;
+			t += prlen;
+			fmt_left -= prlen;
+		} else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
+			*t++ = '%';
+			*t++ = '%';
+			fmt++;
+			fmt_left -= 2;
+		} else {
+			if (fmt_left > 1) {
+				*t++ = ch;
+				fmt_left--;
+			}
+		}
+	}
+	*t = '\0';
+
+	prlen = vsnprintf_int(p, tbuf_left, fmt_cpy, ap);
+	DEC();
+	cnt = p - tbuf;
+
+	/* Output to stderr if requested. */
+	if (data->log_stat & LOG_PERROR) {
+		struct iovec iov[2];
+
+		iov[0].iov_base = stdp;
+		iov[0].iov_len = cnt - (stdp - tbuf);
+		iov[1].iov_base = "\n";
+		iov[1].iov_len = 1;
+		(void)writev(STDERR_FILENO, iov, 2);
+	}
+
+	/* Get connected, output the message to the local logger. */
+	if (!data->opened)
+		openlog_r(data->log_tag, data->log_stat, 0, data);
+	connectlog_r(data);
+
+	/* If we have a SOCK_STREAM connection, also send ASCII NUL as
+	   a record terminator.  */
+	if (LogType == SOCK_STREAM)
+		cnt++;
+
+	/*
+	 * If the send() failed, there are two likely scenarios:
+	 *  1) syslogd was restarted
+	 *  2) /dev/log is out of socket buffer space
+	 * We attempt to reconnect to /dev/log to take care of
+	 * case #1 and keep send()ing data to cover case #2
+	 * to give syslogd a chance to empty its socket buffer.
+	 */
+	if ((error = send(data->log_file, tbuf, cnt, 0)) < 0) {
+		if (errno != ENOBUFS) {
+			disconnectlog_r(data);
+			connectlog_r(data);
+		}
+		do {
+			usleep(1);
+			if ((error = send(data->log_file, tbuf, cnt, 0)) >= 0)
+				break;
+		} while (errno == ENOBUFS);
+	}
+
+	/*
+	 * Output the message to the console; try not to block
+	 * as a blocking console should not stop other processes.
+	 * Make sure the error reported is the one from the syslogd failure.
+	 */
+	if (error == -1 && (data->log_stat & LOG_CONS) &&
+	    (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) {
+		struct iovec iov[2];
+		
+		p = strchr(tbuf, '>') + 1;
+		iov[0].iov_base = p;
+		iov[0].iov_len = cnt - (p - tbuf);
+		iov[1].iov_base = "\r\n";
+		iov[1].iov_len = 2;
+		(void)writev(fd, iov, 2);
+		(void)close(fd);
+	}
+
+	if (data != &sdata)
+		closelog_r(data);
+}
+
+static void
+disconnectlog_r(struct syslog_data *data)
+{
+	/*
+	 * If the user closed the FD and opened another in the same slot,
+	 * that's their problem.  They should close it before calling on
+	 * system services.
+	 */
+	if (data->log_file != -1) {
+		close(data->log_file);
+		data->log_file = -1;
+	}
+	data->connected = 0;		/* retry connect */
+}
+
+static void
+connectlog_r(struct syslog_data *data)
+{
+	struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
+
+again:
+	if (data->log_file == -1) {
+		if ((data->log_file = socket(AF_UNIX, LogType, 0)) == -1)
+			return;
+		(void)fcntl(data->log_file, F_SETFD, 1);
+	}
+	if (data->log_file != -1 && !data->connected) {
+		int old_errno;
+		
+		memset(&SyslogAddr, '\0', sizeof(SyslogAddr));
+		SyslogAddr.sun_family = AF_UNIX;
+		strncpy(SyslogAddr.sun_path, _PATH_LOG,
+		    sizeof(SyslogAddr.sun_path));
+		old_errno = errno;
+		if (connect(data->log_file, (struct sockaddr *)&SyslogAddr,
+		    sizeof(SyslogAddr)) == -1) {
+			int save_errno = errno;
+			(void)close(data->log_file);
+			data->log_file = -1;
+			if (LogType == SOCK_DGRAM && save_errno == EPROTOTYPE) {
+				/* retry with SOCK_STREAM */
+				LogType = SOCK_STREAM;
+				errno = old_errno;
+				goto again;
+			}
+		} else
+			data->connected = 1;
+	}
+}
+
+void
+openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
+{
+	if (ident != NULL)
+		data->log_tag = ident;
+	data->log_stat = logstat;
+	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+		data->log_fac = logfac;
+
+	if (data->log_stat & LOG_NDELAY)	/* open immediately */
+		connectlog_r(data);
+
+	data->opened = 1;	/* ident and facility has been set */
+}
+
+void
+closelog_r(struct syslog_data *data)
+{
+	(void)close(data->log_file);
+	data->log_file = -1;
+	data->connected = 0;
+	data->log_tag = NULL;
+}
+
+/* setlogmask -- set the log mask level */
+int
+setlogmask_r(int pmask, struct syslog_data *data)
+{
+	int omask;
+
+	omask = data->log_mask;
+	if (pmask != 0)
+		data->log_mask = pmask;
+	return (omask);
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
new file mode 100644
index 0000000..eabe83f
--- /dev/null
+++ b/lib/vsprintf.c
@@ -0,0 +1,619 @@
+#ident "$Id: vsprintf.c,v 1.1 2005/05/01 09:48:34 raven Exp $"
+/*
+ *  Stolen from the linux kernel.
+ *
+ *  License: GPL
+ */
+/*------------------ Original Copyright -----------------*/
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+/* 
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
+ * - scnprintf and vscnprintf
+ */
+
+/* Also copied from: */
+
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
+ *                    Matthew Hawkins <matt@mh.dropbear.id.au>
+ * -  Kissed strtok() goodbye
+ */
+/*-------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#define BITS_PER_LONG	__WORDSIZE
+#define PAGE_SIZE	getpagesize()
+
+
+#if BITS_PER_LONG == 64
+
+# define do_div(n,base) ({					\
+	uint32_t __base = (base);				\
+	uint32_t __rem;						\
+	__rem = ((uint64_t)(n)) % __base;			\
+	(n) = ((uint64_t)(n)) / __base;				\
+	__rem;							\
+ })
+
+#elif BITS_PER_LONG == 32
+
+/* Not needed on 64bit architectures */
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+	uint64_t rem = *n;
+	uint64_t b = base;
+	uint64_t res, d = 1;
+	uint32_t high = rem >> 32;
+
+	/* Reduce the thing a bit first */
+	res = 0;
+	if (high >= base) {
+		high /= base;
+		res = (uint64_t) high << 32;
+		rem -= (uint64_t) (high*base) << 32;
+	}
+
+	while ((int64_t)b > 0 && b < rem) {
+		b = b+b;
+		d = d+d;
+	}
+
+	do {
+		if (rem >= b) {
+			rem -= b;
+			res += d;
+		}
+		b >>= 1;
+		d >>= 1;
+	} while (d);
+
+	*n = res;
+	return rem;
+}
+
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({				\
+	uint32_t __base = (base);			\
+	uint32_t __rem;					\
+	(void)(((typeof((n)) *)0) == ((uint64_t *)0));	\
+	if (((n) >> 32) == 0) {				\
+		__rem = (uint32_t)(n) % __base;		\
+		(n) = (uint32_t)(n) / __base;		\
+	} else 						\
+		__rem = __div64_32(&(n), __base);	\
+	__rem;						\
+ })
+
+# else
+
+# error do_div() does not yet support the C64
+
+#endif /* BITS_PER_LONG */
+
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long result = 0,value;
+
+	if (!base) {
+		base = 10;
+		if (*cp == '0') {
+			base = 8;
+			cp++;
+			if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+				cp++;
+				base = 16;
+			}
+		}
+	} else if (base == 16) {
+		if (cp[0] == '0' && toupper(cp[1]) == 'X')
+			cp += 2;
+	}
+	while (isxdigit(*cp) &&
+	       (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+		result = result*base + value;
+		cp++;
+	}
+	if (endp)
+		*endp = (char *)cp;
+	return result;
+}
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+	if(*cp=='-')
+		return -simple_strtoul(cp+1,endp,base);
+	return simple_strtoul(cp,endp,base);
+}
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long long result = 0,value;
+
+	if (!base) {
+		base = 10;
+		if (*cp == '0') {
+			base = 8;
+			cp++;
+			if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+				cp++;
+				base = 16;
+			}
+		}
+	} else if (base == 16) {
+		if (cp[0] == '0' && toupper(cp[1]) == 'X')
+			cp += 2;
+	}
+	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+	    ? toupper(*cp) : *cp)-'A'+10) < base) {
+		result = result*base + value;
+		cp++;
+	}
+	if (endp)
+		*endp = (char *)cp;
+	return result;
+}
+
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+{
+	if(*cp=='-')
+		return -simple_strtoull(cp+1,endp,base);
+	return simple_strtoull(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+	int i=0;
+
+	while (isdigit(**s))
+		i = i*10 + *((*s)++) - '0';
+	return i;
+}
+
+#define ZEROPAD	1		/* pad with zero */
+#define SIGN	2		/* unsigned/signed long */
+#define PLUS	4		/* show plus */
+#define SPACE	8		/* space if plus */
+#define LEFT	16		/* left justified */
+#define SPECIAL	32		/* 0x */
+#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
+{
+	char c,sign,tmp[66];
+	const char *digits;
+	static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+	static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	int i;
+
+	digits = (type & LARGE) ? large_digits : small_digits;
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return NULL;
+	c = (type & ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & SIGN) {
+		if ((signed long long) num < 0) {
+			sign = '-';
+			num = - (signed long long) num;
+			size--;
+		} else if (type & PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & SPECIAL) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0)
+		tmp[i++] = digits[do_div(num,base)];
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(ZEROPAD+LEFT))) {
+		while(size-->0) {
+			if (buf <= end)
+				*buf = ' ';
+			++buf;
+		}
+	}
+	if (sign) {
+		if (buf <= end)
+			*buf = sign;
+		++buf;
+	}
+	if (type & SPECIAL) {
+		if (base==8) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+		} else if (base==16) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+			if (buf <= end)
+				*buf = digits[33];
+			++buf;
+		}
+	}
+	if (!(type & LEFT)) {
+		while (size-- > 0) {
+			if (buf <= end)
+				*buf = c;
+			++buf;
+		}
+	}
+	while (i < precision--) {
+		if (buf <= end)
+			*buf = '0';
+		++buf;
+	}
+	while (i-- > 0) {
+		if (buf <= end)
+			*buf = tmp[i];
+		++buf;
+	}
+	while (size-- > 0) {
+		if (buf <= end)
+			*buf = ' ';
+		++buf;
+	}
+	return buf;
+}
+
+/**
+ * vsnprintf_int - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf. If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf_int(char *buf, size_t size, const char *fmt, va_list args)
+{
+	int len;
+	unsigned long long num;
+	int i, base;
+	char *str, *end, c;
+	const char *s;
+
+	int flags;		/* flags to number() */
+
+	int field_width;	/* width of output field */
+	int precision;		/* min. # of digits for integers; max
+				   number of chars for from string */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+				/* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' changed to 'Z' --davidm 1/25/99 */
+
+	/* Reject out-of-range values early */
+	if ((int) size < 0)
+		return 0;
+
+	str = buf;
+	end = buf + size - 1;
+
+	if (end < buf - 1) {
+		end = ((void *) -1);
+		size = end - buf + 1;
+	}
+
+	for (; *fmt ; ++fmt) {
+		if (*fmt != '%') {
+			if (str <= end)
+				*str = *fmt;
+			++str;
+			continue;
+		}
+
+		/* process flags */
+		flags = 0;
+		repeat:
+			++fmt;		/* this also skips first '%' */
+			switch (*fmt) {
+				case '-': flags |= LEFT; goto repeat;
+				case '+': flags |= PLUS; goto repeat;
+				case ' ': flags |= SPACE; goto repeat;
+				case '#': flags |= SPECIAL; goto repeat;
+				case '0': flags |= ZEROPAD; goto repeat;
+			}
+
+		/* get field width */
+		field_width = -1;
+		if (isdigit(*fmt))
+			field_width = skip_atoi(&fmt);
+		else if (*fmt == '*') {
+			++fmt;
+			/* it's the next argument */
+			field_width = va_arg(args, int);
+			if (field_width < 0) {
+				field_width = -field_width;
+				flags |= LEFT;
+			}
+		}
+
+		/* get the precision */
+		precision = -1;
+		if (*fmt == '.') {
+			++fmt;	
+			if (isdigit(*fmt))
+				precision = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				precision = va_arg(args, int);
+			}
+			if (precision < 0)
+				precision = 0;
+		}
+
+		/* get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+		    *fmt =='Z' || *fmt == 'z') {
+			qualifier = *fmt;
+			++fmt;
+			if (qualifier == 'l' && *fmt == 'l') {
+				qualifier = 'L';
+				++fmt;
+			}
+		}
+
+		/* default base */
+		base = 10;
+
+		switch (*fmt) {
+			case 'c':
+				if (!(flags & LEFT)) {
+					while (--field_width > 0) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				c = (unsigned char) va_arg(args, int);
+				if (str <= end)
+					*str = c;
+				++str;
+				while (--field_width > 0) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
+
+			case 's':
+				s = va_arg(args, char *);
+				if ((unsigned long)s < PAGE_SIZE)
+					s = "<NULL>";
+
+				len = strnlen(s, precision);
+
+				if (!(flags & LEFT)) {
+					while (len < field_width--) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				for (i = 0; i < len; ++i) {
+					if (str <= end)
+						*str = *s;
+					++str; ++s;
+				}
+				while (len < field_width--) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
+
+			case 'p':
+				if (field_width == -1) {
+					field_width = 2*sizeof(void *);
+					flags |= ZEROPAD;
+				}
+				str = number(str, end,
+						(unsigned long) va_arg(args, void *),
+						16, field_width, precision, flags);
+				continue;
+
+
+			case 'n':
+				/* FIXME:
+				* What does C99 say about the overflow case here? */
+				if (qualifier == 'l') {
+					long * ip = va_arg(args, long *);
+					*ip = (str - buf);
+				} else if (qualifier == 'Z' || qualifier == 'z') {
+					size_t * ip = va_arg(args, size_t *);
+					*ip = (str - buf);
+				} else {
+					int * ip = va_arg(args, int *);
+					*ip = (str - buf);
+				}
+				continue;
+
+			case '%':
+				if (str <= end)
+					*str = '%';
+				++str;
+				continue;
+
+				/* integer number formats - set up the flags and "break" */
+			case 'o':
+				base = 8;
+				break;
+
+			case 'X':
+				flags |= LARGE;
+			case 'x':
+				base = 16;
+				break;
+
+			case 'd':
+			case 'i':
+				flags |= SIGN;
+			case 'u':
+				break;
+
+			default:
+				if (str <= end)
+					*str = '%';
+				++str;
+				if (*fmt) {
+					if (str <= end)
+						*str = *fmt;
+					++str;
+				} else {
+					--fmt;
+				}
+				continue;
+		}
+		if (qualifier == 'L')
+			num = va_arg(args, long long);
+		else if (qualifier == 'l') {
+			num = va_arg(args, unsigned long);
+			if (flags & SIGN)
+				num = (signed long) num;
+		} else if (qualifier == 'Z' || qualifier == 'z') {
+			num = va_arg(args, size_t);
+		} else if (qualifier == 'h') {
+			num = (unsigned short) va_arg(args, int);
+			if (flags & SIGN)
+				num = (signed short) num;
+		} else {
+			num = va_arg(args, unsigned int);
+			if (flags & SIGN)
+				num = (signed int) num;
+		}
+		str = number(str, end, num, base,
+				field_width, precision, flags);
+	}
+	if (str <= end)
+		*str = '\0';
+	else if (size > 0)
+		/* don't write out a null byte if the buf size is zero */
+		*end = '\0';
+	/* the trailing null byte doesn't count towards the total
+	* ++str;
+	*/
+	return str-buf;
+}
+
+/**
+ * snprintf_int - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99.  If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ */
+int snprintf_int(char * buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsnprintf_int(buf,size,fmt,args);
+	va_end(args);
+	return i;
+}
+
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 8/8] Fix race which would stop a daemon under high mount rates with failures
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
                   ` (6 preceding siblings ...)
  2011-01-12 22:15 ` [bryder_autofs_4.1.4_PATCH 7/8] Ian Kent's reentrant syslog patch Bill Ryder
@ 2011-01-12 22:25 ` Bill Ryder
  2011-01-26  0:17 ` [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2011-01-12 22:25 UTC (permalink / raw)
  To: autofs

---
 CHANGELOG          |   13 +++++++++++++
 daemon/automount.c |    4 ++--
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index b4959ec..e13e0ac 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,16 @@
+19/07/2010 autofs-4.1.4 - bryder p44
+---------------------------
+  Fix a problem where automount can shut itself down for no good reason.
+  The case I had was  very high rate of failed mounts triggering the
+      if (handle_packet() && errno != EINTR) ; break  
+  piece of code in automount.c:handle_mounts which ended up just shutting down the automounter.
+  The debug statement confirmed it (ap.state was 1 (READY) instead of 6 (SHUTDOWN))
+  The bug is triggered if a child signal is caught when the daemon was not in the middle of a system call - hence errno 
+  was not set to EINTR and handle_packet returned non zero - as in when a mount point didn't exist. 
+  This was  reproducible when using the ignore-stupid-paths option which meant the daemon spent
+  more time in user space handling autofs kernel packets than before.
+
+  
 15/07/2010 autofs-4.1.4 - syslog patch
 --------------------------------------
 
diff --git a/daemon/automount.c b/daemon/automount.c
index 92476b4..0142884 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1729,9 +1729,9 @@ int handle_mounts(char *path)
 		kill(my_pid, SIGSTOP);
 
 	while (ap.state != ST_SHUTDOWN) {
-		if (handle_packet() && errno != EINTR)
-			break;
+		handle_packet();
 	}
+	debug("Shutting down - ap.state is %d if it's not %d (ST_SHUTDOWN) something bad happened ",ap.state,ST_SHUTDOWN);
 
 	/* Mop up remaining kids */
 	handle_child(1);
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE ***
@ 2011-01-25 16:27 Bill Ryder
  2010-12-14  0:44 ` [bryder_autofs_4.1.4_PATCH 1/8] Added the dumpmap option and updated manpage Bill Ryder
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Bill Ryder @ 2011-01-25 16:27 UTC (permalink / raw)
  To: autofs


I'm releasing these patches for anyone still using the old autofs 4.1.4
daemon.

We still use autofs 4.1.4 where I work. 

We have over 4,000 nfs clients using automounter (maps held in LDAP). We use
simple indirect maps. In other words I've only tested LDAP with simple
maps on nfs.

We have found many ways to make fileservers suffer from major performance problems. 

Our preferred behaviour is for the automounter to keep trying to mount
a location until the fileserver becomes less busy. Otherwise we have
to deal with the fallout from EEXIST errors. 

Along the way I've found other stuff which I've included (some of
which only matters because the 4.1.4 daemon forks full processes
rather than using threads).

I have included some other people's patches and have attributed
them to the person I think did the patch in the first place. Apologies
if I've got it wrong!

This published set is meant to clearly publish the work I've done -
but include the bare minimum patches to autofs-4.1.4.tar.gz (from
http://www.kernel.org/pub/linux/daemons/autofs/v4/) 
so that my stuff works and so it's clear what my patches do.

I've included CHANGELOG entries for each patch which hopefully
explains what I've done for each patch.

However,  I use a bunch more patches from the redhat rpms and some
from kernel.org. A current picture of what I really use is available from
https://github.com/bryder/bryder_autofs414

So if you wanted to try this out - github is the place to get it from.

--- patch summary ---

Bill Ryder (8):
  Added the dumpmap option and updated manpage
  Set LDAP_DEPRECATED to prevent coredumps with modern ldap libraries
  Added function names to some debug/crit messages, changed some crits
    to debug
  reinstated the jmoyer ldap-cleanup patch and included man etc updates
  Added option to ignore some highly unlikely paths before forking
    daemon
  Adds options to retry nfs mounts on certain nfs errors
  Ian Kent's reentrant syslog patch
  Fix race which would stop a daemon under high mount rates with
    failures

 CHANGELOG             |  118 ++++++++++
 COPYRIGHT             |   36 +++-
 configure.in          |    1 +
 daemon/automount.c    |  169 ++++++++++++--
 daemon/spawn.c        |   64 +++++-
 include/automount.h   |   43 ++++
 include/syslog.h      |  201 ++++++++++++++++
 lib/Makefile          |    5 +-
 lib/cache.c           |   10 +
 lib/syslog.c          |  383 ++++++++++++++++++++++++++++++
 lib/vsprintf.c        |  619 +++++++++++++++++++++++++++++++++++++++++++++++++
 man/automount.8       |   66 ++++++
 modules/lookup_ldap.c |  329 +++++++++++++++++----------
 modules/mount_nfs.c   |  100 ++++++--
 samples/Makefile      |    2 +-
 15 files changed, 1972 insertions(+), 174 deletions(-)
 create mode 100644 include/syslog.h
 create mode 100644 lib/syslog.c
 create mode 100644 lib/vsprintf.c

-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE ***
  2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
                   ` (7 preceding siblings ...)
  2011-01-12 22:25 ` [bryder_autofs_4.1.4_PATCH 8/8] Fix race which would stop a daemon under high mount rates with failures Bill Ryder
@ 2011-01-26  0:17 ` Bill Ryder
  8 siblings, 0 replies; 11+ messages in thread
From: Bill Ryder @ 2011-01-26  0:17 UTC (permalink / raw)
  To: autofs


[-- Attachment #1.1: Type: text/plain, Size: 67 bytes --]

Wow that's embarrassing. I missed out the subject line.

Doh.
Bill

[-- Attachment #1.2: Type: text/html, Size: 160 bytes --]

[-- Attachment #2: Type: text/plain, Size: 140 bytes --]

_______________________________________________
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [bryder_autofs_4.1.4_PATCH 7/8] Ian Kent's reentrant syslog patch
  2011-01-12 22:15 ` [bryder_autofs_4.1.4_PATCH 7/8] Ian Kent's reentrant syslog patch Bill Ryder
@ 2011-01-27 14:33   ` Ian Kent
  0 siblings, 0 replies; 11+ messages in thread
From: Ian Kent @ 2011-01-27 14:33 UTC (permalink / raw)
  To: Bill Ryder; +Cc: autofs

On Thu, 2011-01-13 at 11:15 +1300, Bill Ryder wrote:
> ---
>  CHANGELOG           |    8 +
>  COPYRIGHT           |   36 +++-
>  daemon/automount.c  |   72 +++++--
>  include/automount.h |   27 +++
>  include/syslog.h    |  201 +++++++++++++++++
>  lib/Makefile        |    5 +-
>  lib/syslog.c        |  383 +++++++++++++++++++++++++++++++
>  lib/vsprintf.c      |  619 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  8 files changed, 1332 insertions(+), 19 deletions(-)
>  create mode 100644 include/syslog.h
>  create mode 100644 lib/syslog.c
>  create mode 100644 lib/vsprintf.c
> 
> diff --git a/CHANGELOG b/CHANGELOG
> index bbf4d3d..b4959ec 100644
> --- a/CHANGELOG
> +++ b/CHANGELOG
> @@ -1,3 +1,11 @@
> +15/07/2010 autofs-4.1.4 - syslog patch
> +--------------------------------------
> +
> +This patch is necessary - especially when using debug syslog messages
> +and testing high mount rates. Without it I've see the daemon wedge in
> +syslog. I'm pretty sure Ian Kent did the patch.

Guilty as charged.

> +
> +
>  14/07/2010 autofs-4.1.4 - bryder p42
>  ------------------------------------
>   Adds retrying to nfs mounts. 
> diff --git a/COPYRIGHT b/COPYRIGHT
> index cf647f8..ee56c0c 100644
> --- a/COPYRIGHT
> +++ b/COPYRIGHT
> @@ -14,4 +14,38 @@ For all software in this distribution unless otherwise indicated:
>     GNU General Public License for more details.
>  
>  Portions Copyright (C) 1999-2000 Jeremy Fitzhardinge
> -Portions Copyright (C) 2001-2003 Ian Kent
> +Portions Copyright (C) 2001-2005 Ian Kent
> +
> +The files lib/syslog.c and include/syslog.h are licenced under the
> +BSD License and require that a copy of the notice ibelow be included in
> +accompanying documentation and be distributed with binary distributions
> +of the code, so be sure to include this file along with any binary
> +distributions derived from this source package.
> +
> +Copyright (c) 1983, 1988, 1993
> +     The Regents of the University of California.  All rights reserved.
> +
> +Redistribution and use in source and binary forms, with or without
> +modification, are permitted provided that the following conditions
> +are met:
> +1. Redistributions of source code must retain the above copyright
> +   notice, this list of conditions and the following disclaimer.
> +2. Redistributions in binary form must reproduce the above copyright
> +   notice, this list of conditions and the following disclaimer in the
> +   documentation and/or other materials provided with the distribution.
> +3. Neither the name of the University nor the names of its contributors
> +   may be used to endorse or promote products derived from this software
> +   without specific prior written permission.
> +
> +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
> +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> +ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
> +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> +SUCH DAMAGE.
> +
> diff --git a/daemon/automount.c b/daemon/automount.c
> index 3567abf..92476b4 100644
> --- a/daemon/automount.c
> +++ b/daemon/automount.c
> @@ -38,13 +38,32 @@
>  #include <sys/poll.h>
>  #include <linux/auto_fs4.h>
>  
> +#include "automount.h"
> +
>  #ifndef NDEBUG
> -#define assert(x)	do { if (!(x)) { syslog(LOG_CRIT, __FILE__ ":%d: assertion failed: " #x, __LINE__); } } while(0)
> +#define assert(x) 						    \
> +	do { 							    \
> +		if (!(x)) {					    \
> +			crit(__FILE__ ":%d: assertion failed: " #x, \
> +				__LINE__);			    \
> +		}						    \
> +	} while(0)
>  #else
>  #define assert(x)	do { } while(0)
>  #endif
>  
> -#include "automount.h"
> +#ifndef NDEBUG
> +#define assert_r(context, x) 					   \
> +	do { 							   \
> +		if (!(x)) {					   \
> +			crit_r(context,				   \
> +				__FILE__ ":%d: assertion failed: ",\
> +				__LINE__);			   \
> +		}						   \
> +	} while(0)
> +#else
> +#define assert_r(context, x)	do { } while(0)
> +#endif
>  
>  const char *program;		/* Initialized with argv[0] */
>  const char *version = VERSION_STRING;	/* Program version */
> @@ -68,6 +87,9 @@ sigset_t sigchld_mask;
>  
>  struct autofs_point ap;
>  
> +/* re-entrant syslog default context data */
> +#define AUTOFS_SYSLOG_CONTEXT {-1, 0, 0, LOG_PID, (const char *)0, LOG_DAEMON, 0xff}
> +
>  volatile struct pending_mount *junk_mounts = NULL;
>  
>  #define CHECK_RATIO     4	/* exp_runfreq = exp_timeout/CHECK_RATIO */
> @@ -481,19 +503,25 @@ static int mount_autofs(char *path)
>  
>  static void nextstate(enum states next)
>  {
> +	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
> +	static struct syslog_data *slc = &syslog_context;
> +
>  	if (write(ap.state_pipe[1], &next, sizeof(next)) != sizeof(next))
> -		error("nextstate: write failed %m");
> +		error_r(slc, "nextstate: write failed %m");
>  }
>  
>  /* Deal with all the signal-driven events in the state machine */
>  static void sig_statemachine(int sig)
>  {
> +	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
> +	static struct syslog_data *slc = &syslog_context;
>  	int save_errno = errno;
>  	enum states next = ap.state;
>  
>  	switch (sig) {
>  	default:		/* all the "can't happen" signals */
> -		error("process %d got unexpected signal %d!", getpid(), sig);
> +		error_r(slc, "process %d got unexpected signal %d!",
> +			getpid(), sig);
>  		break;
>  		/* don't FALLTHROUGH */
>  
> @@ -519,18 +547,21 @@ static void sig_statemachine(int sig)
>  		break;
>  	}
>  
> -	debug("sig %d switching from %d to %d", sig, ap.state, next);
> +	debug_r(slc, "sig %d switching from %d to %d", sig, ap.state, next);
>  
>  	errno = save_errno;
>  }
>  
>  static int send_ready(unsigned int wait_queue_token)
>  {
> +	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
> +	static struct syslog_data *slc = &syslog_context;
> +
>  	if (wait_queue_token == 0)
>  		return 0;
> -	debug("send_ready: token=%d\n", wait_queue_token);
> +	debug_r(slc, "send_ready: token=%d\n", wait_queue_token);
>  	if (ioctl(ap.ioctlfd, AUTOFS_IOC_READY, wait_queue_token) < 0) {
> -		error("AUTOFS_IOC_READY: %m");
> +		error_r(slc, "AUTOFS_IOC_READY: %m");
>  		return 1;
>  	}
>  	return 0;
> @@ -538,11 +569,14 @@ static int send_ready(unsigned int wait_queue_token)
>  
>  static int send_fail(unsigned int wait_queue_token)
>  {
> +	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
> +	static struct syslog_data *slc = &syslog_context;
> +
>  	if (wait_queue_token == 0)
>  		return 0;
> -	debug("send_fail: token=%d\n", wait_queue_token);
> +	debug_r(slc, "send_fail: token=%d\n", wait_queue_token);
>  	if (ioctl(ap.ioctlfd, AUTOFS_IOC_FAIL, wait_queue_token) < 0) {
> -		syslog(LOG_ERR, "AUTOFS_IOC_FAIL: %m");
> +		error_r(slc, "AUTOFS_IOC_FAIL: %m");
>  		return 1;
>  	}
>  	return 0;
> @@ -553,6 +587,8 @@ static int send_fail(unsigned int wait_queue_token)
>     result.  */
>  static enum states handle_child(int hang)
>  {
> +	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
> +	static struct syslog_data *slc = &syslog_context;
>  	pid_t pid;
>  	int status;
>  	enum states next = ST_INVAL;
> @@ -560,7 +596,7 @@ static enum states handle_child(int hang)
>  	while ((pid = waitpid(-1, &status, hang ? 0 : WNOHANG)) > 0) {
>  		struct pending_mount volatile *mt, *volatile *mtp;
>  
> -		debug("handle_child: got pid %d, sig %d (%d), stat %d\n",
> +		debug_r(slc, "handle_child: got pid %d, sig %d (%d), stat %d",
>  			pid, WIFSIGNALED(status),
>  			WTERMSIG(status), WEXITSTATUS(status));
>  
> @@ -606,18 +642,19 @@ static enum states handle_child(int hang)
>  				}
>  
>  				/* Failed shutdown returns to ready */
> -				warn("can't shutdown: filesystem %s still busy",
> -				     ap.path);
> +				warn_r(slc,
> +				   "can't shutdown: filesystem %s still busy",
> +				   ap.path);
>  				alarm(ap.exp_runfreq);
>  				next = ST_READY;
>  				break;
>  
>  			default:
> -				error("bad state %d", ap.state);
> +				error_r(slc, "bad state %d", ap.state);
>  			}
>  
>  			if (next != ST_INVAL)
> -				debug("sigchld: exp "
> +				debug_r(slc, "sigchld: exp "
>  				     "%d finished, switching from %d to %d",
>  				     pid, ap.state, next);
>  
> @@ -633,7 +670,7 @@ static enum states handle_child(int hang)
>  			if (!WIFEXITED(status) && !WIFSIGNALED(status))
>  				break;
>  
> -			debug("sig_child: found pending iop pid %d: "
> +			debug_r(slc, "sig_child: found pending iop pid %d: "
>  			     "signalled %d (sig %d), exit status %d",
>  				pid, WIFSIGNALED(status),
>  				WTERMSIG(status), WEXITSTATUS(status));
> @@ -1530,11 +1567,14 @@ static void setup_signals(__sighandler_t event_handler, __sighandler_t cld_handl
>  /* Deal with the signals recieved by direct mount supervisor */
>  static void sig_supervisor(int sig)
>  {
> +	static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
> +	static struct syslog_data *slc = &syslog_context;
>  	int save_errno = errno;
>  
>  	switch (sig) {
>  	default:		/* all the signals not handled */
> -		error("process %d got unexpected signal %d!", getpid(), sig);
> +		error_r(slc, "process %d got unexpected signal %d!",
> +			getpid(), sig);
>  		return;
>  		/* don't FALLTHROUGH */
>  
> diff --git a/include/automount.h b/include/automount.h
> index b09dd78..72f6c91 100644
> --- a/include/automount.h
> +++ b/include/automount.h
> @@ -15,6 +15,9 @@
>  #include <time.h>
>  #include "config.h"
>  
> +/* OpenBSD re-entrant syslog */
> +#include "syslog.h"
> +
>  /* We MUST have the paths to mount(8) and umount(8) */
>  #ifndef HAVE_MOUNT
>  #error Failed to locate mount(8)!
> @@ -318,5 +321,29 @@ if (do_verbose || do_debug) 		\
>  if (do_debug) 				\
>  	syslog(LOG_DEBUG, msg, ##args);
>  
> +/* Define reentrant logging macros for signal handlers */
> +
> +#define debug_r(context, msg, args...)				\
> +do {								\
> +	if (do_debug)						\
> +		syslog_r(LOG_DEBUG, context, msg, ##args);	\
> +} while (0)
> +
> +#define warn_r(context, msg, args...)				\
> +do {								\
> +	if (do_verbose || do_debug)				\
> +		syslog_r(LOG_WARNING, context, msg, ##args);	\
> +} while (0)
> +
> +#define error_r(context, msg, args...)			\
> +do {							\
> +	syslog_r(LOG_ERR, context, msg, ##args);	\
> +} while (0)
> +
> +#define crit_r(context, msg, args...)			\
> +do {							\
> +	syslog_r(LOG_CRIT, context, msg, ##args);	\
> +} while (0)
> +
>  #endif
>  
> diff --git a/include/syslog.h b/include/syslog.h
> new file mode 100644
> index 0000000..9f1cae4
> --- /dev/null
> +++ b/include/syslog.h
> @@ -0,0 +1,201 @@
> +/*	$OpenBSD: syslog.h,v 1.11 2003/08/24 01:27:07 avsm Exp $	*/
> +/*	$NetBSD: syslog.h,v 1.14 1996/04/03 20:46:44 christos Exp $	*/
> +
> +/*
> + * Copyright (c) 1982, 1986, 1988, 1993
> + *	The Regents of the University of California.  All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. Neither the name of the University nor the names of its contributors
> + *    may be used to endorse or promote products derived from this software
> + *    without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + *	@(#)syslog.h	8.1 (Berkeley) 6/2/93
> + */
> +
> +#ifndef _SYS_SYSLOG_H_
> +#define _SYS_SYSLOG_H_
> +
> +#include <features.h>
> +#define __need___va_list
> +#include <stdarg.h>
> +
> +#define	_PATH_LOG	"/dev/log"
> +
> +/*
> + * priorities/facilities are encoded into a single 32-bit quantity, where the
> + * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
> + * (0-big number).  Both the priorities and the facilities map roughly
> + * one-to-one to strings in the syslogd(8) source code.  This mapping is
> + * included in this file.
> + *
> + * priorities (these are ordered)
> + */
> +#define	LOG_EMERG	0	/* system is unusable */
> +#define	LOG_ALERT	1	/* action must be taken immediately */
> +#define	LOG_CRIT	2	/* critical conditions */
> +#define	LOG_ERR		3	/* error conditions */
> +#define	LOG_WARNING	4	/* warning conditions */
> +#define	LOG_NOTICE	5	/* normal but significant condition */
> +#define	LOG_INFO	6	/* informational */
> +#define	LOG_DEBUG	7	/* debug-level messages */
> +
> +#define	LOG_PRIMASK	0x07	/* mask to extract priority part (internal) */
> +				/* extract priority */
> +#define	LOG_PRI(p)	((p) & LOG_PRIMASK)
> +#define	LOG_MAKEPRI(fac, pri)	(((fac) << 3) | (pri))
> +
> +#ifdef SYSLOG_NAMES
> +#define	INTERNAL_NOPRI	0x10	/* the "no priority" priority */
> +				/* mark "facility" */
> +#define	INTERNAL_MARK	LOG_MAKEPRI(LOG_NFACILITIES, 0)
> +typedef struct _code {
> +	char	*c_name;
> +	int	c_val;
> +} CODE;
> +
> +CODE prioritynames[] = {
> +	{ "alert",	LOG_ALERT },
> +	{ "crit",	LOG_CRIT },
> +	{ "debug",	LOG_DEBUG },
> +	{ "emerg",	LOG_EMERG },
> +	{ "err",	LOG_ERR },
> +	{ "error",	LOG_ERR },		/* DEPRECATED */
> +	{ "info",	LOG_INFO },
> +	{ "none",	INTERNAL_NOPRI },	/* INTERNAL */
> +	{ "notice",	LOG_NOTICE },
> +	{ "panic", 	LOG_EMERG },		/* DEPRECATED */
> +	{ "warn",	LOG_WARNING },		/* DEPRECATED */
> +	{ "warning",	LOG_WARNING },
> +	{ NULL,		-1 },
> +};
> +#endif
> +
> +/* facility codes */
> +#define	LOG_KERN	(0<<3)	/* kernel messages */
> +#define	LOG_USER	(1<<3)	/* random user-level messages */
> +#define	LOG_MAIL	(2<<3)	/* mail system */
> +#define	LOG_DAEMON	(3<<3)	/* system daemons */
> +#define	LOG_AUTH	(4<<3)	/* security/authorization messages */
> +#define	LOG_SYSLOG	(5<<3)	/* messages generated internally by syslogd */
> +#define	LOG_LPR		(6<<3)	/* line printer subsystem */
> +#define	LOG_NEWS	(7<<3)	/* network news subsystem */
> +#define	LOG_UUCP	(8<<3)	/* UUCP subsystem */
> +#define	LOG_CRON	(9<<3)	/* clock daemon */
> +#define	LOG_AUTHPRIV	(10<<3)	/* security/authorization messages (private) */
> +#define	LOG_FTP		(11<<3)	/* ftp daemon */
> +
> +	/* other codes through 15 reserved for system use */
> +#define	LOG_LOCAL0	(16<<3)	/* reserved for local use */
> +#define	LOG_LOCAL1	(17<<3)	/* reserved for local use */
> +#define	LOG_LOCAL2	(18<<3)	/* reserved for local use */
> +#define	LOG_LOCAL3	(19<<3)	/* reserved for local use */
> +#define	LOG_LOCAL4	(20<<3)	/* reserved for local use */
> +#define	LOG_LOCAL5	(21<<3)	/* reserved for local use */
> +#define	LOG_LOCAL6	(22<<3)	/* reserved for local use */
> +#define	LOG_LOCAL7	(23<<3)	/* reserved for local use */
> +
> +#define	LOG_NFACILITIES	24	/* current number of facilities */
> +#define	LOG_FACMASK	0x03f8	/* mask to extract facility part */
> +				/* facility of pri */
> +#define	LOG_FAC(p)	(((p) & LOG_FACMASK) >> 3)
> +
> +#ifdef SYSLOG_NAMES
> +CODE facilitynames[] = {
> +	{ "auth",	LOG_AUTH },
> +	{ "authpriv",	LOG_AUTHPRIV },
> +	{ "cron", 	LOG_CRON },
> +	{ "daemon",	LOG_DAEMON },
> +	{ "ftp",	LOG_FTP },
> +	{ "kern",	LOG_KERN },
> +	{ "lpr",	LOG_LPR },
> +	{ "mail",	LOG_MAIL },
> +	{ "mark", 	INTERNAL_MARK },	/* INTERNAL */
> +	{ "news",	LOG_NEWS },
> +	{ "security",	LOG_AUTH },		/* DEPRECATED */
> +	{ "syslog",	LOG_SYSLOG },
> +	{ "user",	LOG_USER },
> +	{ "uucp",	LOG_UUCP },
> +	{ "local0",	LOG_LOCAL0 },
> +	{ "local1",	LOG_LOCAL1 },
> +	{ "local2",	LOG_LOCAL2 },
> +	{ "local3",	LOG_LOCAL3 },
> +	{ "local4",	LOG_LOCAL4 },
> +	{ "local5",	LOG_LOCAL5 },
> +	{ "local6",	LOG_LOCAL6 },
> +	{ "local7",	LOG_LOCAL7 },
> +	{ NULL,		-1 },
> +};
> +#endif
> +
> +/* Used by reentrant functions */
> +
> +struct syslog_data {
> +	int	log_file;
> +	int	connected;
> +	int	opened;
> +	int	log_stat;
> +	const char 	*log_tag;
> +	int 	log_fac;
> +	int 	log_mask;
> +};
> +
> +#define SYSLOG_DATA_INIT {-1, 0, 0, 0, (const char *)0, LOG_USER, 0xff}
> +
> +/*
> + * arguments to setlogmask.
> + */
> +#define	LOG_MASK(pri)	(1 << (pri))		/* mask for one priority */
> +#define	LOG_UPTO(pri)	((1 << ((pri)+1)) - 1)	/* all priorities through pri */
> +
> +/*
> + * Option flags for openlog.
> + *
> + * LOG_ODELAY no longer does anything.
> + * LOG_NDELAY is the inverse of what it used to be.
> + */
> +#define	LOG_PID		0x01	/* log the pid with each message */
> +#define	LOG_CONS	0x02	/* log on the console if errors in sending */
> +#define	LOG_ODELAY	0x04	/* delay open until first syslog() (default) */
> +#define	LOG_NDELAY	0x08	/* don't delay open */
> +#define	LOG_NOWAIT	0x10	/* don't wait for console forks: DEPRECATED */
> +#define	LOG_PERROR	0x20	/* log to stderr as well */
> +
> +__BEGIN_DECLS
> +void	closelog(void);
> +void	openlog(const char *__ident, int __option, int __facility);
> +int	setlogmask(int __mask);
> +void	syslog(int __pri, const char *__fmt, ...)
> +		__attribute__((__format__(__printf__, 2, 3)));
> +void	vsyslog(int __pri, const char *, __gnuc_va_list __ap)
> +		__attribute__((__format__(__printf__, 2, 0)));
> +void	closelog_r(struct syslog_data *__data);
> +void	openlog_r(const char *__ident, int __option, int __facility, struct syslog_data *__data);
> +int	setlogmask_r(int __mask, struct syslog_data *__data);
> +void	syslog_r(int __pri, struct syslog_data *__data, const char *__fmt, ...)
> +		__attribute__((__format__(__printf__, 3, 4)));
> +void	vsyslog_r(int __pri, struct syslog_data *__data, const char *__fmt, __gnuc_va_list __ap)
> +		__attribute__((__format__(__printf__, 3, 0)));
> +__END_DECLS
> +
> +#endif /* !_SYS_SYSLOG_H_ */
> +
> diff --git a/lib/Makefile b/lib/Makefile
> index 5cc809c..1771b1f 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -9,10 +9,11 @@ include ../Makefile.rules
>  RPCGEN = /usr/bin/rpcgen
>  RANLIB = /usr/bin/ranlib
>  
> -SRCS = cache.c listmount.c cat_path.c rpc_subs.c mounts.c lock.c
> +SRCS = cache.c listmount.c cat_path.c rpc_subs.c mounts.c lock.c syslog.c \
> +	vsprintf.c
>  RPCS = mount.h mount_clnt.c mount_xdr.c
>  OBJS = cache.o mount_clnt.o mount_xdr.o listmount.o \
> -	cat_path.o rpc_subs.o mounts.o lock.o
> +	cat_path.o rpc_subs.o mounts.o lock.o syslog.o vsprintf.o
>  
>  LIB = autofs.a
>  
> diff --git a/lib/syslog.c b/lib/syslog.c
> new file mode 100644
> index 0000000..9e5623e
> --- /dev/null
> +++ b/lib/syslog.c
> @@ -0,0 +1,383 @@
> +#ident "$Id: syslog.c,v 1.1 2005/05/01 09:48:34 raven Exp $"
> +/*
> + * Copyright (c) 1983, 1988, 1993
> + *	The Regents of the University of California.  All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. Neither the name of the University nor the names of its contributors
> + *    may be used to endorse or promote products derived from this software
> + *    without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/uio.h>
> +#include <sys/un.h>
> +#include <netdb.h>
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <paths.h>
> +#include <string.h>
> +#include <time.h>
> +#include <unistd.h>
> +#include <stdarg.h>
> +
> +#include "syslog.h"
> +
> +#define	TBUF_LEN	2048
> +#define	FMT_LEN		1024
> +#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
> +
> +#define	DEC()					\
> +	do {					\
> +		if (prlen < 0)			\
> +			prlen = 0;		\
> +		if (prlen >= tbuf_left)		\
> +			prlen = tbuf_left - 1;	\
> +		p += prlen;			\
> +		tbuf_left -= prlen;		\
> +	} while (0)
> +
> +/* Use our internal printf routines */
> +extern int snprintf_int(char * buf, size_t size, const char * fmt, ...)
> +	__attribute__ ((format (printf, 3, 4)));
> +extern int vsnprintf_int(char *buf, size_t size, const char *fmt, va_list args)
> +	__attribute__ ((format (printf, 3, 0)));
> +
> +static struct syslog_data sdata = SYSLOG_DATA_INIT;
> +static int LogType = SOCK_DGRAM;	/* type of socket connection */
> +
> +extern char	*__progname;		/* Program name, from crt0. */
> +
> +static void	disconnectlog_r(struct syslog_data *);	/* disconnect from syslogd */
> +static void	connectlog_r(struct syslog_data *);	/* (re)connect to syslogd */
> +
> +/*
> + * syslog, vsyslog --
> + *	print message on log file; output is intended for syslogd(8).
> + */
> +void
> +syslog(int pri, const char *fmt, ...)
> +{
> +	va_list ap;
> +
> +	va_start(ap, fmt);
> +	vsyslog(pri, fmt, ap);
> +	va_end(ap);
> +}
> +
> +void
> +vsyslog(int pri, const char *fmt, va_list ap)
> +{
> +	vsyslog_r(pri, &sdata, fmt, ap);
> +}
> +
> +void
> +openlog(const char *ident, int logstat, int logfac)
> +{
> +	openlog_r(ident, logstat, logfac, &sdata);
> +}
> +
> +void
> +closelog(void)
> +{
> +	closelog_r(&sdata);
> +}
> +
> +/* setlogmask -- set the log mask level */
> +int
> +setlogmask(int pmask)
> +{
> +	return setlogmask_r(pmask, &sdata);
> +}
> +
> +/* Reentrant version of syslog, i.e. syslog_r() */
> +
> +void
> +syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
> +{
> +	va_list ap;
> +
> +	va_start(ap, fmt);
> +	vsyslog_r(pri, data, fmt, ap);
> +	va_end(ap);
> +}
> +
> +void
> +vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
> +{
> +	int cnt;
> +	char ch, *p, *t;
> +	time_t now;
> +	int fd, saved_errno, error;
> +	char *stdp = NULL, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
> +	int tbuf_left, fmt_left, prlen;
> +
> +	/* Check for invalid bits. */
> +	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
> +		if (data == &sdata) {
> +			syslog(INTERNALLOG,
> +			    "syslog: unknown facility/priority: %x", pri);
> +		} else {
> +			syslog_r(INTERNALLOG, data,
> +			    "syslog_r: unknown facility/priority: %x", pri);
> +		}
> +		pri &= LOG_PRIMASK|LOG_FACMASK;
> +	}
> +
> +	/* Check priority against setlogmask values. */
> +	if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
> +		return;
> +
> +	saved_errno = errno;
> +
> +	/* Set default facility if none specified. */
> +	if ((pri & LOG_FACMASK) == 0)
> +		pri |= data->log_fac;
> +
> +	/* If we have been called through syslog(), no need for reentrancy. */
> +	if (data == &sdata)
> +		(void)time(&now);
> +
> +	p = tbuf;
> +	tbuf_left = TBUF_LEN;
> +
> +	prlen = snprintf_int(p, tbuf_left, "<%d>", pri);
> +	DEC();
> +
> +	/* 
> +	 * syslogd will expand time automagically for reentrant case, and
> +	 * for normal case, just do like before
> +	 */
> +	if (data == &sdata) {
> +		prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now));
> +		DEC();
> +	}
> +
> +	if (data->log_stat & LOG_PERROR)
> +		stdp = p;
> +	if (data->log_tag == NULL)
> +		data->log_tag = __progname;
> +	if (data->log_tag != NULL) {
> +		prlen = snprintf_int(p, tbuf_left, "%s", data->log_tag);
> +		DEC();
> +	}
> +	if (data->log_stat & LOG_PID) {
> +		prlen = snprintf_int(p, tbuf_left, "[%ld]", (long)getpid());
> +		DEC();
> +	}
> +	if (data->log_tag != NULL) {
> +		if (tbuf_left > 1) {
> +			*p++ = ':';
> +			tbuf_left--;
> +		}
> +		if (tbuf_left > 1) {
> +			*p++ = ' ';
> +			tbuf_left--;
> +		}
> +	}
> +
> +	/* strerror() is not reentrant */
> +
> +	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
> +		if (ch == '%' && fmt[1] == 'm') {
> +			++fmt;
> +			if (data == &sdata) {
> +				prlen = snprintf_int(t, fmt_left, "%s",
> +				    strerror(saved_errno)); 
> +			} else {
> +				prlen = snprintf_int(t, fmt_left, "Error %d",
> +				    saved_errno); 
> +			}
> +			if (prlen < 0)
> +				prlen = 0;
> +			if (prlen >= fmt_left)
> +				prlen = fmt_left - 1;
> +			t += prlen;
> +			fmt_left -= prlen;
> +		} else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
> +			*t++ = '%';
> +			*t++ = '%';
> +			fmt++;
> +			fmt_left -= 2;
> +		} else {
> +			if (fmt_left > 1) {
> +				*t++ = ch;
> +				fmt_left--;
> +			}
> +		}
> +	}
> +	*t = '\0';
> +
> +	prlen = vsnprintf_int(p, tbuf_left, fmt_cpy, ap);
> +	DEC();
> +	cnt = p - tbuf;
> +
> +	/* Output to stderr if requested. */
> +	if (data->log_stat & LOG_PERROR) {
> +		struct iovec iov[2];
> +
> +		iov[0].iov_base = stdp;
> +		iov[0].iov_len = cnt - (stdp - tbuf);
> +		iov[1].iov_base = "\n";
> +		iov[1].iov_len = 1;
> +		(void)writev(STDERR_FILENO, iov, 2);
> +	}
> +
> +	/* Get connected, output the message to the local logger. */
> +	if (!data->opened)
> +		openlog_r(data->log_tag, data->log_stat, 0, data);
> +	connectlog_r(data);
> +
> +	/* If we have a SOCK_STREAM connection, also send ASCII NUL as
> +	   a record terminator.  */
> +	if (LogType == SOCK_STREAM)
> +		cnt++;
> +
> +	/*
> +	 * If the send() failed, there are two likely scenarios:
> +	 *  1) syslogd was restarted
> +	 *  2) /dev/log is out of socket buffer space
> +	 * We attempt to reconnect to /dev/log to take care of
> +	 * case #1 and keep send()ing data to cover case #2
> +	 * to give syslogd a chance to empty its socket buffer.
> +	 */
> +	if ((error = send(data->log_file, tbuf, cnt, 0)) < 0) {
> +		if (errno != ENOBUFS) {
> +			disconnectlog_r(data);
> +			connectlog_r(data);
> +		}
> +		do {
> +			usleep(1);
> +			if ((error = send(data->log_file, tbuf, cnt, 0)) >= 0)
> +				break;
> +		} while (errno == ENOBUFS);
> +	}
> +
> +	/*
> +	 * Output the message to the console; try not to block
> +	 * as a blocking console should not stop other processes.
> +	 * Make sure the error reported is the one from the syslogd failure.
> +	 */
> +	if (error == -1 && (data->log_stat & LOG_CONS) &&
> +	    (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) {
> +		struct iovec iov[2];
> +		
> +		p = strchr(tbuf, '>') + 1;
> +		iov[0].iov_base = p;
> +		iov[0].iov_len = cnt - (p - tbuf);
> +		iov[1].iov_base = "\r\n";
> +		iov[1].iov_len = 2;
> +		(void)writev(fd, iov, 2);
> +		(void)close(fd);
> +	}
> +
> +	if (data != &sdata)
> +		closelog_r(data);
> +}
> +
> +static void
> +disconnectlog_r(struct syslog_data *data)
> +{
> +	/*
> +	 * If the user closed the FD and opened another in the same slot,
> +	 * that's their problem.  They should close it before calling on
> +	 * system services.
> +	 */
> +	if (data->log_file != -1) {
> +		close(data->log_file);
> +		data->log_file = -1;
> +	}
> +	data->connected = 0;		/* retry connect */
> +}
> +
> +static void
> +connectlog_r(struct syslog_data *data)
> +{
> +	struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
> +
> +again:
> +	if (data->log_file == -1) {
> +		if ((data->log_file = socket(AF_UNIX, LogType, 0)) == -1)
> +			return;
> +		(void)fcntl(data->log_file, F_SETFD, 1);
> +	}
> +	if (data->log_file != -1 && !data->connected) {
> +		int old_errno;
> +		
> +		memset(&SyslogAddr, '\0', sizeof(SyslogAddr));
> +		SyslogAddr.sun_family = AF_UNIX;
> +		strncpy(SyslogAddr.sun_path, _PATH_LOG,
> +		    sizeof(SyslogAddr.sun_path));
> +		old_errno = errno;
> +		if (connect(data->log_file, (struct sockaddr *)&SyslogAddr,
> +		    sizeof(SyslogAddr)) == -1) {
> +			int save_errno = errno;
> +			(void)close(data->log_file);
> +			data->log_file = -1;
> +			if (LogType == SOCK_DGRAM && save_errno == EPROTOTYPE) {
> +				/* retry with SOCK_STREAM */
> +				LogType = SOCK_STREAM;
> +				errno = old_errno;
> +				goto again;
> +			}
> +		} else
> +			data->connected = 1;
> +	}
> +}
> +
> +void
> +openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
> +{
> +	if (ident != NULL)
> +		data->log_tag = ident;
> +	data->log_stat = logstat;
> +	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
> +		data->log_fac = logfac;
> +
> +	if (data->log_stat & LOG_NDELAY)	/* open immediately */
> +		connectlog_r(data);
> +
> +	data->opened = 1;	/* ident and facility has been set */
> +}
> +
> +void
> +closelog_r(struct syslog_data *data)
> +{
> +	(void)close(data->log_file);
> +	data->log_file = -1;
> +	data->connected = 0;
> +	data->log_tag = NULL;
> +}
> +
> +/* setlogmask -- set the log mask level */
> +int
> +setlogmask_r(int pmask, struct syslog_data *data)
> +{
> +	int omask;
> +
> +	omask = data->log_mask;
> +	if (pmask != 0)
> +		data->log_mask = pmask;
> +	return (omask);
> +}
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> new file mode 100644
> index 0000000..eabe83f
> --- /dev/null
> +++ b/lib/vsprintf.c
> @@ -0,0 +1,619 @@
> +#ident "$Id: vsprintf.c,v 1.1 2005/05/01 09:48:34 raven Exp $"
> +/*
> + *  Stolen from the linux kernel.
> + *
> + *  License: GPL
> + */
> +/*------------------ Original Copyright -----------------*/
> +/*
> + *  linux/lib/vsprintf.c
> + *
> + *  Copyright (C) 1991, 1992  Linus Torvalds
> + */
> +
> +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
> +/*
> + * Wirzenius wrote this portably, Torvalds fucked it up :-)
> + */
> +
> +/* 
> + * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
> + * - changed to provide snprintf and vsnprintf functions
> + * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
> + * - scnprintf and vscnprintf
> + */
> +
> +/* Also copied from: */
> +
> +/*
> + *  linux/lib/string.c
> + *
> + *  Copyright (C) 1991, 1992  Linus Torvalds
> + */
> +
> +/*
> + * stupid library routines.. The optimized versions should generally be found
> + * as inline code in <asm-xx/string.h>
> + *
> + * These are buggy as well..
> + *
> + * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
> + * -  Added strsep() which will replace strtok() soon (because strsep() is
> + *    reentrant and should be faster). Use only strsep() in new code, please.
> + *
> + * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
> + *                    Matthew Hawkins <matt@mh.dropbear.id.au>
> + * -  Kissed strtok() goodbye
> + */
> +/*-------------------------------------------------------*/
> +
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <ctype.h>
> +#include <sys/types.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +
> +#define BITS_PER_LONG	__WORDSIZE
> +#define PAGE_SIZE	getpagesize()
> +
> +
> +#if BITS_PER_LONG == 64
> +
> +# define do_div(n,base) ({					\
> +	uint32_t __base = (base);				\
> +	uint32_t __rem;						\
> +	__rem = ((uint64_t)(n)) % __base;			\
> +	(n) = ((uint64_t)(n)) / __base;				\
> +	__rem;							\
> + })
> +
> +#elif BITS_PER_LONG == 32
> +
> +/* Not needed on 64bit architectures */
> +uint32_t __div64_32(uint64_t *n, uint32_t base)
> +{
> +	uint64_t rem = *n;
> +	uint64_t b = base;
> +	uint64_t res, d = 1;
> +	uint32_t high = rem >> 32;
> +
> +	/* Reduce the thing a bit first */
> +	res = 0;
> +	if (high >= base) {
> +		high /= base;
> +		res = (uint64_t) high << 32;
> +		rem -= (uint64_t) (high*base) << 32;
> +	}
> +
> +	while ((int64_t)b > 0 && b < rem) {
> +		b = b+b;
> +		d = d+d;
> +	}
> +
> +	do {
> +		if (rem >= b) {
> +			rem -= b;
> +			res += d;
> +		}
> +		b >>= 1;
> +		d >>= 1;
> +	} while (d);
> +
> +	*n = res;
> +	return rem;
> +}
> +
> +/* The unnecessary pointer compare is there
> + * to check for type safety (n must be 64bit)
> + */
> +# define do_div(n,base) ({				\
> +	uint32_t __base = (base);			\
> +	uint32_t __rem;					\
> +	(void)(((typeof((n)) *)0) == ((uint64_t *)0));	\
> +	if (((n) >> 32) == 0) {				\
> +		__rem = (uint32_t)(n) % __base;		\
> +		(n) = (uint32_t)(n) / __base;		\
> +	} else 						\
> +		__rem = __div64_32(&(n), __base);	\
> +	__rem;						\
> + })
> +
> +# else
> +
> +# error do_div() does not yet support the C64
> +
> +#endif /* BITS_PER_LONG */
> +
> +
> +/**
> + * strnlen - Find the length of a length-limited string
> + * @s: The string to be sized
> + * @count: The maximum number of bytes to search
> + */
> +size_t strnlen(const char * s, size_t count)
> +{
> +	const char *sc;
> +
> +	for (sc = s; count-- && *sc != '\0'; ++sc)
> +		/* nothing */;
> +	return sc - s;
> +}
> +
> +/**
> + * simple_strtoul - convert a string to an unsigned long
> + * @cp: The start of the string
> + * @endp: A pointer to the end of the parsed string will be placed here
> + * @base: The number base to use
> + */
> +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
> +{
> +	unsigned long result = 0,value;
> +
> +	if (!base) {
> +		base = 10;
> +		if (*cp == '0') {
> +			base = 8;
> +			cp++;
> +			if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
> +				cp++;
> +				base = 16;
> +			}
> +		}
> +	} else if (base == 16) {
> +		if (cp[0] == '0' && toupper(cp[1]) == 'X')
> +			cp += 2;
> +	}
> +	while (isxdigit(*cp) &&
> +	       (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
> +		result = result*base + value;
> +		cp++;
> +	}
> +	if (endp)
> +		*endp = (char *)cp;
> +	return result;
> +}
> +
> +/**
> + * simple_strtol - convert a string to a signed long
> + * @cp: The start of the string
> + * @endp: A pointer to the end of the parsed string will be placed here
> + * @base: The number base to use
> + */
> +long simple_strtol(const char *cp,char **endp,unsigned int base)
> +{
> +	if(*cp=='-')
> +		return -simple_strtoul(cp+1,endp,base);
> +	return simple_strtoul(cp,endp,base);
> +}
> +
> +/**
> + * simple_strtoull - convert a string to an unsigned long long
> + * @cp: The start of the string
> + * @endp: A pointer to the end of the parsed string will be placed here
> + * @base: The number base to use
> + */
> +unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
> +{
> +	unsigned long long result = 0,value;
> +
> +	if (!base) {
> +		base = 10;
> +		if (*cp == '0') {
> +			base = 8;
> +			cp++;
> +			if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
> +				cp++;
> +				base = 16;
> +			}
> +		}
> +	} else if (base == 16) {
> +		if (cp[0] == '0' && toupper(cp[1]) == 'X')
> +			cp += 2;
> +	}
> +	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
> +	    ? toupper(*cp) : *cp)-'A'+10) < base) {
> +		result = result*base + value;
> +		cp++;
> +	}
> +	if (endp)
> +		*endp = (char *)cp;
> +	return result;
> +}
> +
> +/**
> + * simple_strtoll - convert a string to a signed long long
> + * @cp: The start of the string
> + * @endp: A pointer to the end of the parsed string will be placed here
> + * @base: The number base to use
> + */
> +long long simple_strtoll(const char *cp,char **endp,unsigned int base)
> +{
> +	if(*cp=='-')
> +		return -simple_strtoull(cp+1,endp,base);
> +	return simple_strtoull(cp,endp,base);
> +}
> +
> +static int skip_atoi(const char **s)
> +{
> +	int i=0;
> +
> +	while (isdigit(**s))
> +		i = i*10 + *((*s)++) - '0';
> +	return i;
> +}
> +
> +#define ZEROPAD	1		/* pad with zero */
> +#define SIGN	2		/* unsigned/signed long */
> +#define PLUS	4		/* show plus */
> +#define SPACE	8		/* space if plus */
> +#define LEFT	16		/* left justified */
> +#define SPECIAL	32		/* 0x */
> +#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
> +
> +static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
> +{
> +	char c,sign,tmp[66];
> +	const char *digits;
> +	static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
> +	static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
> +	int i;
> +
> +	digits = (type & LARGE) ? large_digits : small_digits;
> +	if (type & LEFT)
> +		type &= ~ZEROPAD;
> +	if (base < 2 || base > 36)
> +		return NULL;
> +	c = (type & ZEROPAD) ? '0' : ' ';
> +	sign = 0;
> +	if (type & SIGN) {
> +		if ((signed long long) num < 0) {
> +			sign = '-';
> +			num = - (signed long long) num;
> +			size--;
> +		} else if (type & PLUS) {
> +			sign = '+';
> +			size--;
> +		} else if (type & SPACE) {
> +			sign = ' ';
> +			size--;
> +		}
> +	}
> +	if (type & SPECIAL) {
> +		if (base == 16)
> +			size -= 2;
> +		else if (base == 8)
> +			size--;
> +	}
> +	i = 0;
> +	if (num == 0)
> +		tmp[i++]='0';
> +	else while (num != 0)
> +		tmp[i++] = digits[do_div(num,base)];
> +	if (i > precision)
> +		precision = i;
> +	size -= precision;
> +	if (!(type&(ZEROPAD+LEFT))) {
> +		while(size-->0) {
> +			if (buf <= end)
> +				*buf = ' ';
> +			++buf;
> +		}
> +	}
> +	if (sign) {
> +		if (buf <= end)
> +			*buf = sign;
> +		++buf;
> +	}
> +	if (type & SPECIAL) {
> +		if (base==8) {
> +			if (buf <= end)
> +				*buf = '0';
> +			++buf;
> +		} else if (base==16) {
> +			if (buf <= end)
> +				*buf = '0';
> +			++buf;
> +			if (buf <= end)
> +				*buf = digits[33];
> +			++buf;
> +		}
> +	}
> +	if (!(type & LEFT)) {
> +		while (size-- > 0) {
> +			if (buf <= end)
> +				*buf = c;
> +			++buf;
> +		}
> +	}
> +	while (i < precision--) {
> +		if (buf <= end)
> +			*buf = '0';
> +		++buf;
> +	}
> +	while (i-- > 0) {
> +		if (buf <= end)
> +			*buf = tmp[i];
> +		++buf;
> +	}
> +	while (size-- > 0) {
> +		if (buf <= end)
> +			*buf = ' ';
> +		++buf;
> +	}
> +	return buf;
> +}
> +
> +/**
> + * vsnprintf_int - Format a string and place it in a buffer
> + * @buf: The buffer to place the result into
> + * @size: The size of the buffer, including the trailing null space
> + * @fmt: The format string to use
> + * @args: Arguments for the format string
> + *
> + * The return value is the number of characters which would
> + * be generated for the given input, excluding the trailing
> + * '\0', as per ISO C99. If you want to have the exact
> + * number of characters written into @buf as return value
> + * (not including the trailing '\0'), use vscnprintf. If the
> + * return is greater than or equal to @size, the resulting
> + * string is truncated.
> + *
> + * Call this function if you are already dealing with a va_list.
> + * You probably want snprintf instead.
> + */
> +int vsnprintf_int(char *buf, size_t size, const char *fmt, va_list args)
> +{
> +	int len;
> +	unsigned long long num;
> +	int i, base;
> +	char *str, *end, c;
> +	const char *s;
> +
> +	int flags;		/* flags to number() */
> +
> +	int field_width;	/* width of output field */
> +	int precision;		/* min. # of digits for integers; max
> +				   number of chars for from string */
> +	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
> +				/* 'z' support added 23/7/1999 S.H.    */
> +				/* 'z' changed to 'Z' --davidm 1/25/99 */
> +
> +	/* Reject out-of-range values early */
> +	if ((int) size < 0)
> +		return 0;
> +
> +	str = buf;
> +	end = buf + size - 1;
> +
> +	if (end < buf - 1) {
> +		end = ((void *) -1);
> +		size = end - buf + 1;
> +	}
> +
> +	for (; *fmt ; ++fmt) {
> +		if (*fmt != '%') {
> +			if (str <= end)
> +				*str = *fmt;
> +			++str;
> +			continue;
> +		}
> +
> +		/* process flags */
> +		flags = 0;
> +		repeat:
> +			++fmt;		/* this also skips first '%' */
> +			switch (*fmt) {
> +				case '-': flags |= LEFT; goto repeat;
> +				case '+': flags |= PLUS; goto repeat;
> +				case ' ': flags |= SPACE; goto repeat;
> +				case '#': flags |= SPECIAL; goto repeat;
> +				case '0': flags |= ZEROPAD; goto repeat;
> +			}
> +
> +		/* get field width */
> +		field_width = -1;
> +		if (isdigit(*fmt))
> +			field_width = skip_atoi(&fmt);
> +		else if (*fmt == '*') {
> +			++fmt;
> +			/* it's the next argument */
> +			field_width = va_arg(args, int);
> +			if (field_width < 0) {
> +				field_width = -field_width;
> +				flags |= LEFT;
> +			}
> +		}
> +
> +		/* get the precision */
> +		precision = -1;
> +		if (*fmt == '.') {
> +			++fmt;	
> +			if (isdigit(*fmt))
> +				precision = skip_atoi(&fmt);
> +			else if (*fmt == '*') {
> +				++fmt;
> +				/* it's the next argument */
> +				precision = va_arg(args, int);
> +			}
> +			if (precision < 0)
> +				precision = 0;
> +		}
> +
> +		/* get the conversion qualifier */
> +		qualifier = -1;
> +		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
> +		    *fmt =='Z' || *fmt == 'z') {
> +			qualifier = *fmt;
> +			++fmt;
> +			if (qualifier == 'l' && *fmt == 'l') {
> +				qualifier = 'L';
> +				++fmt;
> +			}
> +		}
> +
> +		/* default base */
> +		base = 10;
> +
> +		switch (*fmt) {
> +			case 'c':
> +				if (!(flags & LEFT)) {
> +					while (--field_width > 0) {
> +						if (str <= end)
> +							*str = ' ';
> +						++str;
> +					}
> +				}
> +				c = (unsigned char) va_arg(args, int);
> +				if (str <= end)
> +					*str = c;
> +				++str;
> +				while (--field_width > 0) {
> +					if (str <= end)
> +						*str = ' ';
> +					++str;
> +				}
> +				continue;
> +
> +			case 's':
> +				s = va_arg(args, char *);
> +				if ((unsigned long)s < PAGE_SIZE)
> +					s = "<NULL>";
> +
> +				len = strnlen(s, precision);
> +
> +				if (!(flags & LEFT)) {
> +					while (len < field_width--) {
> +						if (str <= end)
> +							*str = ' ';
> +						++str;
> +					}
> +				}
> +				for (i = 0; i < len; ++i) {
> +					if (str <= end)
> +						*str = *s;
> +					++str; ++s;
> +				}
> +				while (len < field_width--) {
> +					if (str <= end)
> +						*str = ' ';
> +					++str;
> +				}
> +				continue;
> +
> +			case 'p':
> +				if (field_width == -1) {
> +					field_width = 2*sizeof(void *);
> +					flags |= ZEROPAD;
> +				}
> +				str = number(str, end,
> +						(unsigned long) va_arg(args, void *),
> +						16, field_width, precision, flags);
> +				continue;
> +
> +
> +			case 'n':
> +				/* FIXME:
> +				* What does C99 say about the overflow case here? */
> +				if (qualifier == 'l') {
> +					long * ip = va_arg(args, long *);
> +					*ip = (str - buf);
> +				} else if (qualifier == 'Z' || qualifier == 'z') {
> +					size_t * ip = va_arg(args, size_t *);
> +					*ip = (str - buf);
> +				} else {
> +					int * ip = va_arg(args, int *);
> +					*ip = (str - buf);
> +				}
> +				continue;
> +
> +			case '%':
> +				if (str <= end)
> +					*str = '%';
> +				++str;
> +				continue;
> +
> +				/* integer number formats - set up the flags and "break" */
> +			case 'o':
> +				base = 8;
> +				break;
> +
> +			case 'X':
> +				flags |= LARGE;
> +			case 'x':
> +				base = 16;
> +				break;
> +
> +			case 'd':
> +			case 'i':
> +				flags |= SIGN;
> +			case 'u':
> +				break;
> +
> +			default:
> +				if (str <= end)
> +					*str = '%';
> +				++str;
> +				if (*fmt) {
> +					if (str <= end)
> +						*str = *fmt;
> +					++str;
> +				} else {
> +					--fmt;
> +				}
> +				continue;
> +		}
> +		if (qualifier == 'L')
> +			num = va_arg(args, long long);
> +		else if (qualifier == 'l') {
> +			num = va_arg(args, unsigned long);
> +			if (flags & SIGN)
> +				num = (signed long) num;
> +		} else if (qualifier == 'Z' || qualifier == 'z') {
> +			num = va_arg(args, size_t);
> +		} else if (qualifier == 'h') {
> +			num = (unsigned short) va_arg(args, int);
> +			if (flags & SIGN)
> +				num = (signed short) num;
> +		} else {
> +			num = va_arg(args, unsigned int);
> +			if (flags & SIGN)
> +				num = (signed int) num;
> +		}
> +		str = number(str, end, num, base,
> +				field_width, precision, flags);
> +	}
> +	if (str <= end)
> +		*str = '\0';
> +	else if (size > 0)
> +		/* don't write out a null byte if the buf size is zero */
> +		*end = '\0';
> +	/* the trailing null byte doesn't count towards the total
> +	* ++str;
> +	*/
> +	return str-buf;
> +}
> +
> +/**
> + * snprintf_int - Format a string and place it in a buffer
> + * @buf: The buffer to place the result into
> + * @size: The size of the buffer, including the trailing null space
> + * @fmt: The format string to use
> + * @...: Arguments for the format string
> + *
> + * The return value is the number of characters which would be
> + * generated for the given input, excluding the trailing null,
> + * as per ISO C99.  If the return is greater than or equal to
> + * @size, the resulting string is truncated.
> + */
> +int snprintf_int(char * buf, size_t size, const char *fmt, ...)
> +{
> +	va_list args;
> +	int i;
> +
> +	va_start(args, fmt);
> +	i=vsnprintf_int(buf,size,fmt,args);
> +	va_end(args);
> +	return i;
> +}
> +

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-01-27 14:33 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-25 16:27 [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder
2010-12-14  0:44 ` [bryder_autofs_4.1.4_PATCH 1/8] Added the dumpmap option and updated manpage Bill Ryder
2010-12-14  2:36 ` [bryder_autofs_4.1.4_PATCH 2/8] Set LDAP_DEPRECATED to prevent coredumps with modern ldap libraries Bill Ryder
2010-12-20  1:10 ` [bryder_autofs_4.1.4_PATCH 3/8] Added function names to some debug/crit messages, changed some crits to debug Bill Ryder
2010-12-20 19:30 ` [bryder_autofs_4.1.4_PATCH 4/8] reinstated the jmoyer ldap-cleanup patch and included man etc updates Bill Ryder
2011-01-10  1:27 ` [bryder_autofs_4.1.4_PATCH 5/8] Added option to ignore some highly unlikely paths before forking daemon Bill Ryder
2011-01-12  2:44 ` [bryder_autofs_4.1.4_PATCH 6/8] Adds options to retry nfs mounts on certain nfs errors Bill Ryder
2011-01-12 22:15 ` [bryder_autofs_4.1.4_PATCH 7/8] Ian Kent's reentrant syslog patch Bill Ryder
2011-01-27 14:33   ` Ian Kent
2011-01-12 22:25 ` [bryder_autofs_4.1.4_PATCH 8/8] Fix race which would stop a daemon under high mount rates with failures Bill Ryder
2011-01-26  0:17 ` [bryder_autofs_4.1.4_PATCH 0/8] *** SUBJECT HERE *** Bill Ryder

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.