--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 2db9b39..dd08880 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -31,6 +31,7 @@
+ - fix forground logging and add option to man page.
+ - remove unjustified, nasty comment about krb5 package.
+ - fix deadlock in submount mount module.
++- fix lack of ferror() checking when reading files.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 930b13f..70a3b9d 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -978,7 +978,7 @@ static void *do_read_master(void *arg)
+ if (status)
+ fatal(status);
+
+- defaults_read_config();
++ defaults_read_config(1);
+
+ status = master_read_master(master, age, readall);
+
+@@ -1465,7 +1465,7 @@ int main(int argc, char *argv[])
+
+ program = argv[0];
+
+- defaults_read_config();
++ defaults_read_config(0);
+
+ kpkt_len = get_kpkt_len();
+ timeout = defaults_get_timeout();
+diff --git a/include/defaults.h b/include/defaults.h
+index 46393d9..0e0e2a5 100644
+--- a/include/defaults.h
++++ b/include/defaults.h
+@@ -41,7 +41,7 @@
+ struct ldap_schema;
+ struct ldap_searchdn;
+
+-unsigned int defaults_read_config(void);
++unsigned int defaults_read_config(unsigned int);
+ const char *defaults_get_master_map(void);
+ unsigned int defaults_get_timeout(void);
+ unsigned int defaults_get_browse_mode(void);
+diff --git a/lib/defaults.c b/lib/defaults.c
+index bf1ceed..2cccf20 100644
+--- a/lib/defaults.c
++++ b/lib/defaults.c
+@@ -280,7 +280,7 @@ struct list_head *defaults_get_uris(void)
+ * is valid bourne shell script without spaces around "="
+ * and that it has valid values.
+ */
+-unsigned int defaults_read_config(void)
++unsigned int defaults_read_config(unsigned int to_syslog)
+ {
+ FILE *f;
+ char buf[MAX_LINE_LEN];
+@@ -312,9 +312,16 @@ unsigned int defaults_read_config(void)
+ ;
+ }
+
+- if (!feof(f)) {
+- fprintf(stderr, "fgets returned error %d while reading %s\n",
+- ferror(f), DEFAULTS_CONFIG_FILE);
++ if (!feof(f) || ferror(f)) {
++ if (!to_syslog) {
++ fprintf(stderr,
++ "fgets returned error %d while reading %s\n",
++ ferror(f), DEFAULTS_CONFIG_FILE);
++ } else {
++ error(LOGOPT_ANY,
++ "fgets returned error %d while reading %s",
++ ferror(f), DEFAULTS_CONFIG_FILE);
++ }
+ fclose(f);
+ return 0;
+ }
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index 6346602..31ee0fb 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -442,6 +442,11 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ if (!entry) {
+ if (feof(f))
+ break;
++ if (ferror(f)) {
++ warn(LOGOPT_ANY, MODPREFIX
++ "error reading map %s", ctxt->mapname);
++ break;
++ }
+ continue;
+ }
+
+@@ -683,6 +688,11 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+ if (!entry) {
+ if (feof(f))
+ break;
++ if (ferror(f)) {
++ warn(LOGOPT_ANY, MODPREFIX
++ "error reading map %s", ctxt->mapname);
++ break;
++ }
+ continue;
+ }
+
+@@ -848,6 +858,12 @@ static int lookup_one(struct autofs_point *ap,
+
+ if (feof(f))
+ break;
++
++ if (ferror(f)) {
++ warn(LOGOPT_ANY, MODPREFIX
++ "error reading map %s", ctxt->mapname);
++ break;
++ }
+ }
+
+ fclose(f);
+@@ -907,6 +923,12 @@ static int lookup_wild(struct autofs_point *ap, struct lookup_context *ctxt)
+
+ if (feof(f))
+ break;
++
++ if (ferror(f)) {
++ warn(LOGOPT_ANY, MODPREFIX
++ "error reading map %s", ctxt->mapname);
++ break;
++ }
+ }
+
+ fclose(f);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 172d0cd..6931791 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -1,3 +1,7 @@
++??/??/2007 autofs-5.0.3
++-----------------------
++- include krb5.h in lookup_ldap.h (some openssl doesn't implicitly include it).
++
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+ - fix return check for getpwuid_r and getgrgid_r.
+diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
+index e1c5b4e..0a9deca 100644
+--- a/include/lookup_ldap.h
++++ b/include/lookup_ldap.h
+@@ -7,6 +7,7 @@
+ #include <openssl/err.h>
+ #include <sasl/sasl.h>
+ #include <libxml/tree.h>
++#include <krb5.h>
+ #endif
+
+ struct lookup_context {
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 1c147c5..74d39fd 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -41,6 +41,7 @@
+ - fix handling of LDAP base dns with spaces.
+ - handle MTAB_NOTUPDATED status return from mount.
+ - when default master map, auto.master, is used also check for auto_master.
++- fix schema selection in LDAP schema discovery.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index dfb3054..8719af9 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -193,10 +193,11 @@ static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt
+ LDAPMessage *result = NULL, *e;
+ struct ldap_searchdn *sdns = NULL;
+ char *attrs[2];
++ struct berval **value;
+ int scope;
+ int rv, l;
+
+- attrs[0] = LDAP_NO_ATTRS;
++ attrs[0] = (char *) key;
+ attrs[1] = NULL;
+
+ if (!ctxt->mapname && !ctxt->base) {
+@@ -283,7 +284,8 @@ static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt
+ }
+
+ e = ldap_first_entry(ldap, result);
+- if (e) {
++ if (e && (value = ldap_get_values_len(ldap, e, key))) {
++ ldap_value_free_len(value);
+ dn = ldap_get_dn(ldap, e);
+ debug(logopt, MODPREFIX "found query dn %s", dn);
+ } else {
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index ef549cf..08afa7c 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -23,6 +23,7 @@
+ - add random selection as a master map entry option.
+ - fix couple of edge case parse fails of timeout option.
+ - check for "*" when looking up wildcard in LDAP.
++- fix LDAP schema discovery.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index a7b315e..9c18ca1 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -1009,6 +1009,15 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ free_context(ctxt);
+ return 1;
+ }
++ } else {
++ const char *class = ctxt->schema->map_class;
++ const char *key = ctxt->schema->map_attr;
++ if (!get_query_dn(ldap, ctxt, class, key)) {
++ unbind_ldap_connection(ldap, ctxt);
++ error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
++ free_context(ctxt);
++ return 1;
++ }
+ }
+ unbind_ldap_connection(ldap, ctxt);
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 92013ce..c36017a 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -19,6 +19,7 @@
+ - fix "nosymlink" option handling and add desription to man page.
+ - fix don't fail on empty master map.
+ - if there's no "automount" entry in nsswitch.conf use "files" source.
++- add LDAP schema discovery if no schema is configured.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/include/defaults.h b/include/defaults.h
+index ef58467..9aec11a 100644
+--- a/include/defaults.h
++++ b/include/defaults.h
+@@ -43,11 +43,8 @@ unsigned int defaults_get_timeout(void);
+ unsigned int defaults_get_browse_mode(void);
+ unsigned int defaults_get_logging(void);
+ const char *defaults_get_ldap_server(void);
+-const char *defaults_get_map_obj_class(void);
+-const char *defaults_get_entry_obj_class(void);
+-const char *defaults_get_map_attr(void);
+-const char *defaults_get_entry_attr(void);
+-const char *defaults_get_value_attr(void);
++struct ldap_schema *defaults_get_default_schema(void);
++struct ldap_schema *defaults_get_schema(void);
+ unsigned int defaults_get_append_options(void);
+ const char *defaults_get_auth_conf_file(void);
+
+diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
+index 0a9deca..1378b9e 100644
+--- a/include/lookup_ldap.h
++++ b/include/lookup_ldap.h
+@@ -10,6 +10,14 @@
+ #include <krb5.h>
+ #endif
+
++struct ldap_schema {
++ char *map_class;
++ char *map_attr;
++ char *entry_class;
++ char *entry_attr;
++ char *value_attr;
++};
++
+ struct lookup_context {
+ char *mapname;
+
+@@ -22,11 +30,7 @@ struct lookup_context {
+ int version;
+
+ /* LDAP lookup configuration */
+- char *map_obj_class;
+- char *entry_obj_class;
+- char *map_attr;
+- char *entry_attr;
+- char *value_attr;
++ struct ldap_schema *schema;
+
+ /* TLS and SASL authentication information */
+ char *auth_conf;
+diff --git a/lib/defaults.c b/lib/defaults.c
+index 4b4acba..b146f13 100644
+--- a/lib/defaults.c
++++ b/lib/defaults.c
+@@ -18,6 +18,7 @@
+ #include <string.h>
+
+ #include "defaults.h"
++#include "lookup_ldap.h"
+ #include "log.h"
+
+ #define DEFAULTS_CONFIG_FILE AUTOFS_CONF_DIR "/autofs"
+@@ -41,16 +42,8 @@
+ #define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE"
+
+ static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME;
+-
+-static const char *default_ldap_server = DEFAULT_LDAP_SERVER;
+-
+-static const char *default_map_obj_class = DEFAULT_MAP_OBJ_CLASS;
+-static const char *default_entry_obj_class = DEFAULT_ENTRY_OBJ_CLASS;
+-static const char *default_map_attr = DEFAULT_MAP_ATTR;
+-static const char *default_entry_attr = DEFAULT_ENTRY_ATTR;
+-static const char *default_value_attr = DEFAULT_VALUE_ATTR;
+-
+-static const char *default_auth_conf_file = DEFAULT_AUTH_CONF_FILE;
++static const char *default_ldap_server = DEFAULT_LDAP_SERVER;
++static const char *default_auth_conf_file = DEFAULT_AUTH_CONF_FILE;
+
+ static char *get_env_string(const char *name)
+ {
+@@ -285,59 +278,120 @@ const char *defaults_get_ldap_server(void)
+ return (const char *) server;
+ }
+
+-const char *defaults_get_map_obj_class(void)
++struct ldap_schema *defaults_get_default_schema(void)
+ {
+- char *moc;
++ struct ldap_schema *schema;
++ char *mc, *ma, *ec, *ea, *va;
+
+- moc = get_env_string(ENV_NAME_MAP_OBJ_CLASS);
+- if (!moc)
+- return strdup(default_map_obj_class);
++ mc = strdup(DEFAULT_MAP_OBJ_CLASS);
++ if (!mc)
++ return NULL;
+
+- return (const char *) moc;
+-}
++ ma = strdup(DEFAULT_MAP_ATTR);
++ if (!ma) {
++ free(mc);
++ return NULL;
++ }
+
+-const char *defaults_get_entry_obj_class(void)
+-{
+- char *eoc;
++ ec = strdup(DEFAULT_ENTRY_OBJ_CLASS);
++ if (!ec) {
++ free(mc);
++ free(ma);
++ return NULL;
++ }
+
+- eoc = get_env_string(ENV_NAME_ENTRY_OBJ_CLASS);
+- if (!eoc)
+- return strdup(default_entry_obj_class);
++ ea = strdup(DEFAULT_ENTRY_ATTR);
++ if (!ea) {
++ free(mc);
++ free(ma);
++ free(ec);
++ return NULL;
++ }
+
+- return (const char *) eoc;
+-}
++ va = strdup(DEFAULT_VALUE_ATTR);
++ if (!va) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ return NULL;
++ }
+
+-const char *defaults_get_map_attr(void)
+-{
+- char *ma;
++ schema = malloc(sizeof(struct ldap_schema));
++ if (!schema) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ free(va);
++ return NULL;
++ }
+
+- ma = get_env_string(ENV_NAME_MAP_ATTR);
+- if (!ma)
+- return strdup(default_map_attr);
++ schema->map_class = mc;
++ schema->map_attr = ma;
++ schema->entry_class = ec;
++ schema->entry_attr = ea;
++ schema->value_attr = va;
+
+- return (const char *) ma;
++ return schema;
+ }
+
+-const char *defaults_get_entry_attr(void)
++struct ldap_schema *defaults_get_schema(void)
+ {
+- char *ea;
++ struct ldap_schema *schema;
++ char *mc, *ma, *ec, *ea, *va;
+
+- ea = get_env_string(ENV_NAME_ENTRY_ATTR);
+- if (!ea)
+- return strdup(default_entry_attr);
++ mc = get_env_string(ENV_NAME_MAP_OBJ_CLASS);
++ if (!mc)
++ return NULL;
+
+- return (const char *) ea;
+-}
++ ma = get_env_string(ENV_NAME_MAP_ATTR);
++ if (!ma) {
++ free(mc);
++ return NULL;
++ }
+
+-const char *defaults_get_value_attr(void)
+-{
+- char *va;
++ ec = get_env_string(ENV_NAME_ENTRY_OBJ_CLASS);
++ if (!ec) {
++ free(mc);
++ free(ma);
++ return NULL;
++ }
++
++ ea = get_env_string(ENV_NAME_ENTRY_ATTR);
++ if (!ea) {
++ free(mc);
++ free(ma);
++ free(ec);
++ return NULL;
++ }
+
+ va = get_env_string(ENV_NAME_VALUE_ATTR);
+- if (!va)
+- return strdup(default_value_attr);
++ if (!va) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ return NULL;
++ }
++
++ schema = malloc(sizeof(struct ldap_schema));
++ if (!schema) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ free(va);
++ return NULL;
++ }
++
++ schema->map_class = mc;
++ schema->map_attr = ma;
++ schema->entry_class = ec;
++ schema->entry_attr = ea;
++ schema->value_attr = va;
+
+- return (const char *) va;
++ return schema;
+ }
+
+ unsigned int defaults_get_append_options(void)
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index 69c796e..249c9a7 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -191,17 +191,25 @@ The old style
+ is also understood. Alternatively, the type can be obtained from the Name Service Switch
+ configuration, in which case the map name alone must be given.
+ .P
+-The default LDAP schema is the NIS schema described in RFC 2307.
+-Entries in the nisMap schema are \fBnisObject\fP objects in
++If no schema is set in the autofs configuration then autofs will check
++each of the commonly used schema for a valid entry and if one is found
++it will used for subsequent lookups.
++.P
++There are three common schemas in use:
++.TP
++.I nisMap
++Entries in the \fBnisMap\fP schema are \fBnisObject\fP objects in
+ the specified subtree, where the \fBcn\fP attribute is the key
+ (the wildcard key is "/"), and the \fBnisMapEntry\fP attribute
+ contains the information used by the automounter.
+-.P
+-Entries in the automountMap schema are \fBautomount\fP objects in
+-the specified subtree, where the \fBcn\fP or \fBautomountKey\fP attribute
+-(depending on local usage) is the key (the wildcard key is "/"), and the
+-\fBautomountInformation\fP attribute contains the information used by the
+-automounter.
++.TP
++.I automountMap
++The \fBautomountMap\fP schema has two variations that differ in the attribute
++used for the map key. Entries in the automountMap schema are \fBautomount\fP
++objects in the specified subtree, where the \fBcn\fP or \fBautomountKey\fP
++attribute (depending on local usage) is the key (the wildcard key is "/"),
++and the \fBautomountInformation\fP attribute contains the information used
++by the automounter. Note that the \fBcn\fP attribute is case insensitive.
+ .P
+ The object classes and attributes used for accessing automount maps in
+ LDAP can be changed by setting entries in the autofs configuration
+@@ -209,61 +217,44 @@ located in
+ .nh
+ .BR @@autofsconfdir@@/autofs .
+ .hy
++.TP
++.B NOTE:
++If a schema is given in the configuration then all the schema configuration
++values must be set, any partial schema specification will be ignored.
+ .P
+ The configuration settings available are:
+ .TP
+-\fBMAP_OBJECT_CLASS\fP
+-The map object class. Its Default value is "nisMap". In the
+-.nh
+-automountMap
+-.hy
+-schema this corresponds to the class
+-.nh
+-.BR automountMap .
+-.hy
++.B MAP_OBJECT_CLASS
++The map object class. In the \fBnisMap\fP schema this corresponds to the class
++\fBnisMap\fP and in the \fBautomountMap\fP schema it corresponds to the class
++\fBautomountMap\fP.
+ .TP
+ .B ENTRY_OBJECT_CLASS
+-The map entry object class. Its default value is \fBnisObject\fP.
+-In the automountMap schema this corresponds to the class
+-.nh
+-.BR automount .
+-.hy
++The map entry object class. In the \fBnisMap\fP schema this corresponds
++to the class \fBnisObject\fP and in the \fBautomountMap\fP schema it
++corresponds to the class \fBautomount\fP.
+ .TP
+ .B MAP_ATTRIBUTE
+ The attribute used to identify the name of the map to which this
+-entry belongs. Its default value is
+-.nh
+-.BR nisMapName .
+-.hy
+-In the
+-.nh
+-automountMap
+-.hy
+-schema this corresponds to the attributes \fBou\fP or
+-.nh
+-.BR automountMapName .
+-.hy
++entry belongs. In the \fBnisMap\fP schema this corresponds to the attribute
++\fBnisMapName\fP and in the \fBautomountMap\fP schema it corresponds to the
++attribute \fBou\fP or \fBautomountMapName\fP.
+ .TP
+ .B ENTRY_ATTRIBUTE
+-The attribute used to identify a map key. Its default value is
+-In the
+-.nh
+-automountMap
+-.hy
+-schema this corresponds to the attribute
+-.nh
+-.BR automountKey .
+-.hy
++The attribute used to identify a map key. In the \fBnisMap\fP schema this
++corresponds to the attribute \fBcn\fP and in the \fBautomountMap\fP schema
++it corresponds to the attribute \fBautomountKey\fP.
+ .TP
+ .B VALUE_ATTRIBUTE
+-The attribute used to identify the value of the map entry. Its default
+-value is
+-.nh
+-.BR BnisMapEntry .
+-.hy
+-In the automountMap schema this corresponds to the attribute
+-.nh
+-.BR automountInformation .
++The attribute used to identify the value of the map entry. In the \fBnisMap\fP
++schema this corresponds to the attribute \fBnisMapEntry\fP and in the \fBautomountMap\fP
++schema it corresponds to the attribute \fBautomountInformation\fP.
++.TP
++.B NOTE:
++It is essential that entries use class and attribute in a consistent
++manner for correct operation of autofs. For example mixing \fBcn\fP and
++\fBautomountKey\fP attributes in \fBautomount\fP schema map entries won't
++work as expected.
+ .SH LDAP AUTHENTICATION, ENCRYPTED AND CERTIFIED CONNECTIONS
+ LDAP authenticated binds, TLS encrypted connections and certification
+ may be used by setting appropriate values in the autofs authentication
+diff --git a/man/automount.8 b/man/automount.8
+index fc1846a..da67a5c 100644
+--- a/man/automount.8
++++ b/man/automount.8
+@@ -102,6 +102,8 @@ started they will be recoverd unless they are no longer present in
+ the map in which case they need to umounted manually.
+ .SH "SEE ALSO"
+ .BR autofs (5),
++.BR autofs (8),
++.BR auto.master (5),
+ .BR mount (8).
+ .SH BUGS
+ Don't know, I've fixed everything I know about.
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index a412797..d5e666b 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -42,6 +42,13 @@
+
+ int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+
++static struct ldap_schema common_schema[] = {
++ {"nisMap", "nisMapName", "nisObject", "cn", "nisMapEntry"},
++ {"automountMap", "ou", "automount", "cn", "automountInformation"},
++ {"automountMap", "automountMapName", "automount", "automountKey", "automountInformation"},
++};
++static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema);
++
+ int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
+ {
+ int rv;
+@@ -738,54 +745,15 @@ done:
+ return 1;
+ }
+
+-static int get_default_schema(struct lookup_context *ctxt)
+-{
+- ctxt->map_obj_class = (char *) defaults_get_map_obj_class();
+- if (!ctxt->map_obj_class)
+- return 0;
+-
+- ctxt->entry_obj_class = (char *) defaults_get_entry_obj_class();
+- if (!ctxt->entry_obj_class)
+- goto free_moc;
+-
+- ctxt->map_attr = (char *) defaults_get_map_attr();
+- if (!ctxt->map_attr)
+- goto free_eoc;
+-
+- ctxt->entry_attr = (char *) defaults_get_entry_attr();
+- if (!ctxt->entry_attr)
+- goto free_ma;
+-
+- ctxt->value_attr = (char *) defaults_get_value_attr();
+- if (!ctxt->value_attr)
+- goto free_ea;
+-
+- return 1;
+-
+-free_ea:
+- free(ctxt->entry_attr);
+-free_ma:
+- free(ctxt->map_attr);
+-free_eoc:
+- free(ctxt->entry_obj_class);
+-free_moc:
+- free(ctxt->map_obj_class);
+-
+- ctxt->map_obj_class = NULL;
+- ctxt->entry_obj_class = NULL;
+- ctxt->map_attr = NULL;
+- ctxt->entry_attr = NULL;
+-
+- return 0;
+-}
+-
+ static void free_context(struct lookup_context *ctxt)
+ {
+- if (ctxt->map_obj_class) {
+- free(ctxt->map_obj_class);
+- free(ctxt->entry_obj_class);
+- free(ctxt->map_attr);
+- free(ctxt->entry_attr);
++ if (ctxt->schema) {
++ free(ctxt->schema->map_class);
++ free(ctxt->schema->map_attr);
++ free(ctxt->schema->entry_class);
++ free(ctxt->schema->entry_attr);
++ free(ctxt->schema->value_attr);
++ free(ctxt->schema);
+ }
+ if (ctxt->auth_conf)
+ free(ctxt->auth_conf);
+@@ -808,19 +776,15 @@ static void free_context(struct lookup_context *ctxt)
+ return;
+ }
+
+-static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt)
++static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
+ {
+ char buf[PARSE_MAX_BUF];
+ char *query, *dn;
+ LDAPMessage *result, *e;
+- char *class, *key;
+ char *attrs[2];
+ int scope;
+ int rv, l;
+
+- class = ctxt->map_obj_class;
+- key = ctxt->map_attr;
+-
+ attrs[0] = LDAP_NO_ATTRS;
+ attrs[1] = NULL;
+
+@@ -890,6 +854,90 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt)
+ return 1;
+ }
+
++static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
++{
++ struct ldap_schema *schema;
++ char *mc, *ma, *ec, *ea, *va;
++
++ mc = strdup(s->map_class);
++ if (!mc)
++ return NULL;
++
++ ma = strdup(s->map_attr);
++ if (!ma) {
++ free(mc);
++ return NULL;
++ }
++
++ ec = strdup(s->entry_class);
++ if (!ec) {
++ free(mc);
++ free(ma);
++ return NULL;
++ }
++
++ ea = strdup(s->entry_attr);
++ if (!ea) {
++ free(mc);
++ free(ma);
++ free(ec);
++ return NULL;
++ }
++
++ va = strdup(s->value_attr);
++ if (!va) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ return NULL;
++ }
++
++ schema = malloc(sizeof(struct ldap_schema));
++ if (!schema) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ free(va);
++ return NULL;
++ }
++
++ schema->map_class = mc;
++ schema->map_attr = ma;
++ schema->entry_class = ec;
++ schema->entry_attr = ea;
++ schema->value_attr = va;
++
++ return schema;
++}
++
++static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
++{
++ struct ldap_schema *schema;
++ unsigned int i;
++
++ if (ctxt->schema)
++ return 0;
++
++ for (i = 0; i < common_schema_count; i++) {
++ const char *class = common_schema[i].map_class;
++ const char *key = common_schema[i].map_attr;
++ if (get_query_dn(ldap, ctxt, class, key)) {
++ schema = alloc_common_schema(&common_schema[i]);
++ if (!schema) {
++ error(LOGOPT_ANY,
++ MODPREFIX "failed to allocate schema");
++ return 0;
++ }
++ ctxt->schema = schema;
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
+ /*
+ * This initializes a context (persistent non-global data) for queries to
+ * this module. Return zero if we succeed.
+@@ -926,13 +974,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ return 1;
+ }
+
+- /* Get default schema for queries */
+- if (!get_default_schema(ctxt)) {
+- error(LOGOPT_ANY, MODPREFIX "cannot set default schema");
+- free_context(ctxt);
+- return 1;
+- }
+-
+ #ifdef WITH_SASL
+ /*
+ * Determine which authentication mechanism to use. We sanity-
+@@ -954,13 +995,22 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ return 1;
+ }
+
+- ret = get_query_dn(ldap, ctxt);
+- unbind_ldap_connection(ldap, ctxt);
+- if (!ret) {
+- error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
+- free_context(ctxt);
+- return 1;
++ /*
++ * Get default schema for queries.
++ * If the schema isn't defined in the configuration then check for
++ * presence of a map dn in the common schemas.
++ */
++ ctxt->schema = defaults_get_schema();
++ if (!ctxt->schema) {
++ if (!find_query_dn(ldap, ctxt)) {
++ unbind_ldap_connection(ldap, ctxt);
++ error(LOGOPT_ANY,
++ MODPREFIX "failed to find valid query dn");
++ free_context(ctxt);
++ return 1;
++ }
+ }
++ unbind_ldap_connection(ldap, ctxt);
+
+ /* Open the parser, if we can. */
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+@@ -990,9 +1040,9 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ int scope = LDAP_SCOPE_SUBTREE;
+ LDAP *ldap;
+
+- class = ctxt->entry_obj_class;
+- entry = ctxt->entry_attr;
+- info = ctxt->value_attr;
++ class = ctxt->schema->entry_class;
++ entry = ctxt->schema->entry_attr;
++ info = ctxt->schema->value_attr;
+
+ attrs[0] = entry;
+ attrs[1] = info;
+@@ -1141,9 +1191,9 @@ static int read_one_map(struct autofs_point *ap,
+
+ mc = source->mc;
+
+- class = ctxt->entry_obj_class;
+- entry = ctxt->entry_attr;
+- info = ctxt->value_attr;
++ class = ctxt->schema->entry_class;
++ entry = ctxt->schema->entry_attr;
++ info = ctxt->schema->value_attr;
+
+ attrs[0] = entry;
+ attrs[1] = info;
+@@ -1438,9 +1488,9 @@ static int lookup_one(struct autofs_point *ap,
+ return CHE_FAIL;
+ }
+
+- class = ctxt->entry_obj_class;
+- entry = ctxt->entry_attr;
+- info = ctxt->value_attr;
++ class = ctxt->schema->entry_class;
++ entry = ctxt->schema->entry_attr;
++ info = ctxt->schema->value_attr;
+
+ attrs[0] = entry;
+ attrs[1] = info;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 91903e9..6b16b0f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -2,6 +2,7 @@
+ -----------------------
+ - include krb5.h in lookup_ldap.h (some openssl doesn't implicitly include it).
+ - correct initialization of local var in parse_server_string.
++- add missing "multi" map support.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 06fcecc..70b9e02 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -456,8 +456,12 @@ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time
+ }
+
+ if (map->type) {
+- debug(ap->logopt,
+- "reading map %s %s", map->type, map->argv[0]);
++ if (!strncmp(map->type, "multi", 5))
++ debug(ap->logopt, "reading multi map");
++ else
++ debug(ap->logopt,
++ "reading map %s %s",
++ map->type, map->argv[0]);
+ result = do_read_map(ap, map, age);
+ map = map->next;
+ continue;
+diff --git a/include/automount.h b/include/automount.h
+index 85e6e9c..106ed0a 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -192,6 +192,7 @@ char *cache_get_offset(const char *prefix, char *offset, int start, struct list_
+ /* Utility functions */
+
+ char **add_argv(int argc, char **argv, char *str);
++char **append_argv(int argc1, char **argv1, int argc2, char **argv2);
+ const char **copy_argv(int argc, const char **argv);
+ int compare_argv(int argc1, const char **argv1, int argc2, const char **argv2);
+ int free_argv(int argc, const char **argv);
+diff --git a/lib/args.c b/lib/args.c
+index 9e35388..fbfb004 100644
+--- a/lib/args.c
++++ b/lib/args.c
+@@ -62,6 +62,45 @@ char **add_argv(int argc, char **argv, char *str)
+ return vector;
+ }
+
++char **append_argv(int argc1, char **argv1, int argc2, char **argv2)
++{
++ char **vector;
++ size_t vector_size;
++ int len, i, j;
++
++ len = argc1 + argc2;
++ vector_size = (len + 1) * sizeof(char *);
++ vector = (char **) realloc(argv1, vector_size);
++ if (!vector) {
++ free_argv(argc1, (const char **) argv1);
++ free_argv(argc2, (const char **) argv2);
++ return NULL;
++ }
++
++ for (i = argc1, j = 0; i <= len; i++, j++) {
++ if (argv2[j]) {
++ vector[i] = strdup(argv2[j]);
++ if (!vector[i]) {
++ error(LOGOPT_ANY, "failed to strdup arg");
++ break;
++ }
++ } else
++ vector[i] = NULL;
++ }
++
++ if (i < len) {
++ free_argv(len, (const char **) vector);
++ free_argv(argc2, (const char **) argv2);
++ return NULL;
++ }
++
++ vector[len] = NULL;
++
++ free_argv(argc2, (const char **) argv2);
++
++ return vector;
++}
++
+ const char **copy_argv(int argc, const char **argv)
+ {
+ char **vector;
+diff --git a/lib/master_parse.y b/lib/master_parse.y
+index 8d2be02..f9cba05 100644
+--- a/lib/master_parse.y
++++ b/lib/master_parse.y
+@@ -22,6 +22,7 @@
+ #include <string.h>
+ #include <stdlib.h>
+ #include <stdarg.h>
++#include <ctype.h>
+ #include <sys/ioctl.h>
+
+ #include "automount.h"
+@@ -44,6 +45,7 @@ extern void master_set_scan_buffer(const char *);
+ static char *master_strdup(char *);
+ static void local_init_vars(void);
+ static void local_free_vars(void);
++static int add_multi_mapstr(void);
+
+ static int master_error(const char *s);
+ static int master_notify(const char *s);
+@@ -53,6 +55,8 @@ static char *type;
+ static char *format;
+ static long timeout;
+ static unsigned ghost;
++static char **tmp_argv;
++static int tmp_argc;
+ static char **local_argv;
+ static int local_argc;
+
+@@ -89,7 +93,7 @@ static int master_fprintf(FILE *, char *, ...);
+ %token COMMENT
+ %token MAP
+ %token OPT_TIMEOUT OPT_NOGHOST OPT_GHOST OPT_VERBOSE OPT_DEBUG
+-%token COLON COMMA NL
++%token COLON COMMA NL DDASH
+ %type <strtype> map
+ %type <strtype> options
+ %type <strtype> dn
+@@ -103,6 +107,7 @@ static int master_fprintf(FILE *, char *, ...);
+ %token <strtype> NILL
+ %token <strtype> SPACE
+ %token <strtype> EQUAL
++%token <strtype> MULTITYPE
+ %token <strtype> MAPTYPE
+ %token <strtype> DNSERVER
+ %token <strtype> DNATTR
+@@ -126,7 +131,7 @@ file: {
+ ;
+
+ line:
+- | PATH map
++ | PATH mapspec
+ {
+ path = master_strdup($1);
+ if (!path) {
+@@ -134,14 +139,49 @@ line:
+ YYABORT;
+ }
+ }
+- | PATH map options
++ | PATH MULTITYPE maplist
+ {
++ char *tmp;
++
++ tmp = strchr($2, ':');
++ if (tmp)
++ *tmp = '\0';
++ else {
++ int len = strlen($2);
++ while (len-- && isblank($2[len]))
++ $2[len] = '\0';
++ if (len < 4) {
++ master_notify($2);
++ local_free_vars();
++ YYABORT;
++ }
++ }
++
+ path = master_strdup($1);
+ if (!path) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+- }
++
++ if ((tmp = strchr($2, ',')))
++ *tmp++ = '\0';
++
++ type = master_strdup($2);
++ if (!type) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
++ if (tmp) {
++ format = master_strdup(tmp);
++ if (!format) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
++ }
++ }
+ | PATH COLON { master_notify($1); YYABORT; }
+ | PATH OPTION { master_notify($2); YYABORT; }
+ | PATH NILL { master_notify($2); YYABORT; }
+@@ -157,25 +197,89 @@ line:
+ | COMMENT { YYABORT; }
+ ;
+
+-map: PATH
++mapspec: map
++ {
++ local_argc = tmp_argc;
++ local_argv = tmp_argv;
++ tmp_argc = 0;
++ tmp_argv = NULL;
++ }
++ | map options
++ {
++ local_argc = tmp_argc;
++ local_argv = tmp_argv;
++ tmp_argc = 0;
++ tmp_argv = NULL;
++ }
++ ;
++
++maplist: map
++ {
++ if (!add_multi_mapstr()) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
++ }
++ | map options
++ {
++ if (!add_multi_mapstr()) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
++ }
++ | maplist DDASH map
+ {
+ local_argc++;
+- local_argv = add_argv(local_argc, local_argv, $1);
++ local_argv = add_argv(local_argc, local_argv, "--");
+ if (!local_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
++ if (!add_multi_mapstr()) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
+ }
+- | MAPNAME
++ | maplist DDASH map options
+ {
+ local_argc++;
+- local_argv = add_argv(local_argc, local_argv, $1);
++ local_argv = add_argv(local_argc, local_argv, "--");
+ if (!local_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
++ if (!add_multi_mapstr()) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
++ }
++ ;
++
++map: PATH
++ {
++ tmp_argc++;
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
++ if (!tmp_argv) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
++ }
++ | MAPNAME
++ {
++ tmp_argc++;
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
++ if (!tmp_argv) {
++ master_error("memory allocation error");
++ local_free_vars();
++ YYABORT;
++ }
+ }
+ | MAPHOSTS
+ {
+@@ -200,9 +304,9 @@ map: PATH
+ local_free_vars();
+ YYABORT;
+ }
+- local_argc++;
+- local_argv = add_argv(local_argc, local_argv, $1);
+- if (!local_argv) {
++ tmp_argc++;
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
++ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+@@ -227,9 +331,9 @@ map: PATH
+ YYABORT;
+ }
+ }
+- local_argc++;
+- local_argv = add_argv(local_argc, local_argv, $3);
+- if (!local_argv) {
++ tmp_argc++;
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $3);
++ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+@@ -254,9 +358,9 @@ map: PATH
+ YYABORT;
+ }
+ }
+- local_argc++;
+- local_argv = add_argv(local_argc, local_argv, $3);
+- if (!local_argv) {
++ tmp_argc++;
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $3);
++ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+@@ -281,25 +385,25 @@ map: PATH
+ YYABORT;
+ }
+ }
+- local_argc++;
+- local_argv = add_argv(local_argc, local_argv, $3);
+- if (!local_argv) {
++ tmp_argc++;
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $3);
++ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ /* Add back the type for lookup_ldap.c to handle ldaps */
+- if (*local_argv[0]) {
+- tmp = malloc(strlen(type) + strlen(local_argv[0]) + 2);
++ if (*tmp_argv[0]) {
++ tmp = malloc(strlen(type) + strlen(tmp_argv[0]) + 2);
+ if (!tmp) {
+ local_free_vars();
+ YYABORT;
+ }
+ strcpy(tmp, type);
+ strcat(tmp, ":");
+- strcat(tmp, local_argv[0]);
+- free(local_argv[0]);
+- local_argv[0] = tmp;
++ strcat(tmp, tmp_argv[0]);
++ free(tmp_argv[0]);
++ tmp_argv[0] = tmp;
+ }
+ }
+ ;
+@@ -441,9 +545,9 @@ daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; }
+
+ mount_option: OPTION
+ {
+- local_argc++;
+- local_argv = add_argv(local_argc, local_argv, $1);
+- if (!local_argv) {
++ tmp_argc++;
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $1);
++ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+@@ -494,6 +598,8 @@ static void local_init_vars(void)
+ debug = 0;
+ timeout = -1;
+ ghost = defaults_get_browse_mode();
++ tmp_argv = NULL;
++ tmp_argc = 0;
+ local_argv = NULL;
+ local_argc = 0;
+ }
+@@ -509,8 +615,62 @@ static void local_free_vars(void)
+ if (format)
+ free(format);
+
+- if (local_argv)
++ if (local_argv) {
+ free_argv(local_argc, (const char **) local_argv);
++ local_argv = NULL;
++ local_argc = 0;
++ }
++
++ if (tmp_argv) {
++ free_argv(tmp_argc, (const char **) tmp_argv);
++ tmp_argv = NULL;
++ tmp_argc = 0;
++ }
++}
++
++static int add_multi_mapstr(void)
++{
++ /* We need the individual map types for a multi map */
++ if (!type) {
++ if (tmp_argc > 0 && *tmp_argv[0] == '/')
++ type = strdup("file");
++ else
++ return 0;
++ }
++
++ if (format) {
++ char *tmp = realloc(type, strlen(type) + strlen(format) + 2);
++ if (!tmp)
++ return 0;
++ type = tmp;
++ strcat(type, ",");
++ strcat(type, format);
++ free(format);
++ format = NULL;
++ }
++
++ local_argc++;
++ local_argv = add_argv(local_argc, local_argv, type);
++ if (!local_argv) {
++ free(type);
++ type = NULL;
++ return 0;
++ }
++
++ local_argv = append_argv(local_argc, local_argv, tmp_argc, tmp_argv);
++ if (!local_argv) {
++ free(type);
++ type = NULL;
++ return 0;
++ }
++ local_argc += tmp_argc;
++
++ tmp_argc = 0;
++ tmp_argv = NULL;
++ free(type);
++ type = NULL;
++
++ return 1;
+ }
+
+ void master_init_scan(void)
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index ee2a4eb..0548de1 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -27,6 +27,7 @@ static void master_echo(void); /* forward definition */
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <ctype.h>
+ #include "master_parse.tab.h"
+
+ /*
+@@ -110,7 +111,9 @@ DNATTRSTR {AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}
+ DNNAMESTR ([[:alnum:]_.\-]+)
+
+ INTMAP (-hosts|-null)
+-MTYPE ((file|program|yp|nis|nisplus|ldap|ldaps|hesiod|userdir)(,(sun|hesiod))?)
++MULTI ((multi)(,(sun|hesiod))?[\:]?{OPTWS})
++MULTISEP ([\-]{2}[[:blank:]]+)
++MTYPE ((file|program|yp|nis|nisplus|ldap|ldaps|hesiod|userdir)(,(sun|hesiod))?)
+
+
+ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+@@ -184,11 +187,18 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ <MAPSTR>{
+ {OPTWS}\\\n{OPTWS} {}
+
++ {MULTI} {
++ strcpy(master_lval.strtype, master_text);
++ return(MULTITYPE);
++ }
++
+ {MTYPE}/":" {
+ strcpy(master_lval.strtype, master_text);
+ return(MAPTYPE);
+ }
+
++ {MULTISEP} { return(DDASH); }
++
+ ":" { return(COLON); }
+
+ "-hosts" {
+@@ -298,6 +308,11 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ <OPTSTR>{
+ {OPTWS}\\\n{OPTWS} {}
+
++ {MULTISEP} {
++ BEGIN(MAPSTR);
++ return(DDASH);
++ }
++
+ {OPTTOUT} { return(OPT_TIMEOUT); }
+
+ {NUMBER} {
+diff --git a/modules/lookup_multi.c b/modules/lookup_multi.c
+index 00ab28e..38ca36c 100644
+--- a/modules/lookup_multi.c
++++ b/modules/lookup_multi.c
+@@ -45,7 +45,7 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+ struct lookup_context *ctxt;
+ char buf[MAX_ERR_BUF];
+ char *map, *mapfmt;
+- int i, j, an;
++ int i, an;
+ char *estr;
+
+ ctxt = malloc(sizeof(struct lookup_context));
+@@ -73,7 +73,7 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+
+ memcpy(ctxt->argl, argv, (argc + 1) * sizeof(const char *));
+
+- for (i = j = an = 0; ctxt->argl[an]; an++) {
++ for (i = an = 0; ctxt->argl[an]; an++) {
+ if (ctxt->m[i].argc == 0) {
+ ctxt->m[i].argv = &ctxt->argl[an];
+ }
+@@ -100,9 +100,12 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+ if (!(ctxt->m[i].mod = open_lookup(map, MODPREFIX,
+ mapfmt ? mapfmt : my_mapfmt,
+ ctxt->m[i].argc - 1,
+- ctxt->m[i].argv + 1)))
++ ctxt->m[i].argv + 1))) {
+ error(LOGOPT_ANY, MODPREFIX "error opening module");
++ free(map);
+ goto error_out;
++ }
++ free(map);
+ }
+
+ *context = ctxt;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 6b16b0f..d66b8fc 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -3,6 +3,7 @@
+ - include krb5.h in lookup_ldap.h (some openssl doesn't implicitly include it).
+ - correct initialization of local var in parse_server_string.
+ - add missing "multi" map support.
++- add multi nsswitch lookup.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/master_parse.y b/lib/master_parse.y
+index f9cba05..ab2895d 100644
+--- a/lib/master_parse.y
++++ b/lib/master_parse.y
+@@ -45,6 +45,7 @@ extern void master_set_scan_buffer(const char *);
+ static char *master_strdup(char *);
+ static void local_init_vars(void);
+ static void local_free_vars(void);
++static void trim_maptype(char *);
+ static int add_multi_mapstr(void);
+
+ static int master_error(const char *s);
+@@ -141,21 +142,9 @@ line:
+ }
+ | PATH MULTITYPE maplist
+ {
+- char *tmp;
+-
+- tmp = strchr($2, ':');
+- if (tmp)
+- *tmp = '\0';
+- else {
+- int len = strlen($2);
+- while (len-- && isblank($2[len]))
+- $2[len] = '\0';
+- if (len < 4) {
+- master_notify($2);
+- local_free_vars();
+- YYABORT;
+- }
+- }
++ char *tmp = NULL;
++
++ trim_maptype($2);
+
+ path = master_strdup($1);
+ if (!path) {
+@@ -312,81 +301,93 @@ map: PATH
+ YYABORT;
+ }
+ }
+- | MAPTYPE COLON PATH
++ | MAPTYPE PATH
+ {
+ char *tmp = NULL;
+
++ trim_maptype($1);
++
+ if ((tmp = strchr($1, ',')))
+ *tmp++ = '\0';
+
+ type = master_strdup($1);
+ if (!type) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ if (tmp) {
+ format = master_strdup(tmp);
+ if (!format) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ }
+ tmp_argc++;
+- tmp_argv = add_argv(tmp_argc, tmp_argv, $3);
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $2);
+ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ }
+- | MAPTYPE COLON MAPNAME
++ | MAPTYPE MAPNAME
+ {
+ char *tmp = NULL;
+
++ trim_maptype($1);
++
+ if ((tmp = strchr($1, ',')))
+ *tmp++ = '\0';
+
+ type = master_strdup($1);
+ if (!type) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ if (tmp) {
+ format = master_strdup(tmp);
+ if (!format) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ }
+ tmp_argc++;
+- tmp_argv = add_argv(tmp_argc, tmp_argv, $3);
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $2);
+ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ }
+- | MAPTYPE COLON dn
++ | MAPTYPE dn
+ {
+ char *tmp = NULL;
+
++ trim_maptype($1);
++
+ if ((tmp = strchr($1, ',')))
+ *tmp++ = '\0';
+
+ type = master_strdup($1);
+ if (!type) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ if (tmp) {
+ format = master_strdup(tmp);
+ if (!format) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+ }
+ tmp_argc++;
+- tmp_argv = add_argv(tmp_argc, tmp_argv, $3);
++ tmp_argv = add_argv(tmp_argc, tmp_argv, $2);
+ if (!tmp_argv) {
+ master_error("memory allocation error");
+ local_free_vars();
+@@ -396,6 +397,7 @@ map: PATH
+ if (*tmp_argv[0]) {
+ tmp = malloc(strlen(type) + strlen(tmp_argv[0]) + 2);
+ if (!tmp) {
++ master_error("memory allocation error");
+ local_free_vars();
+ YYABORT;
+ }
+@@ -628,33 +630,47 @@ static void local_free_vars(void)
+ }
+ }
+
+-static int add_multi_mapstr(void)
++static void trim_maptype(char *type)
+ {
+- /* We need the individual map types for a multi map */
+- if (!type) {
+- if (tmp_argc > 0 && *tmp_argv[0] == '/')
+- type = strdup("file");
+- else
+- return 0;
++ char *tmp;
++
++ tmp = strchr(type, ':');
++ if (tmp)
++ *tmp = '\0';
++ else {
++ int len = strlen(type);
++ while (len-- && isblank(type[len]))
++ type[len] = '\0';
+ }
++ return;
++}
++
++static int add_multi_mapstr(void)
++{
++ if (type) {
++ /* If type given and format is non-null add it back */
++ if (format) {
++ int len = strlen(type) + strlen(format) + 2;
++ char *tmp = realloc(type, len);
++ if (!tmp)
++ return 0;
++ type = tmp;
++ strcat(type, ",");
++ strcat(type, format);
++ free(format);
++ format = NULL;
++ }
+
+- if (format) {
+- char *tmp = realloc(type, strlen(type) + strlen(format) + 2);
+- if (!tmp)
++ local_argc++;
++ local_argv = add_argv(local_argc, local_argv, type);
++ if (!local_argv) {
++ free(type);
++ type = NULL;
+ return 0;
+- type = tmp;
+- strcat(type, ",");
+- strcat(type, format);
+- free(format);
+- format = NULL;
+- }
++ }
+
+- local_argc++;
+- local_argv = add_argv(local_argc, local_argv, type);
+- if (!local_argv) {
+ free(type);
+ type = NULL;
+- return 0;
+ }
+
+ local_argv = append_argv(local_argc, local_argv, tmp_argc, tmp_argv);
+@@ -667,8 +683,6 @@ static int add_multi_mapstr(void)
+
+ tmp_argc = 0;
+ tmp_argv = NULL;
+- free(type);
+- type = NULL;
+
+ return 1;
+ }
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 0548de1..9bfeefa 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -111,9 +111,9 @@ DNATTRSTR {AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}
+ DNNAMESTR ([[:alnum:]_.\-]+)
+
+ INTMAP (-hosts|-null)
+-MULTI ((multi)(,(sun|hesiod))?[\:]?{OPTWS})
++MULTI ((multi)(,(sun|hesiod))?(:{OPTWS}|{WS}))
+ MULTISEP ([\-]{2}[[:blank:]]+)
+-MTYPE ((file|program|yp|nis|nisplus|ldap|ldaps|hesiod|userdir)(,(sun|hesiod))?)
++MTYPE ((file|program|yp|nis|nisplus|ldap|ldaps|hesiod|userdir)(,(sun|hesiod))?(:{OPTWS}|{WS}))
+
+
+ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+@@ -192,7 +192,7 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ return(MULTITYPE);
+ }
+
+- {MTYPE}/":" {
++ {MTYPE} {
+ strcpy(master_lval.strtype, master_text);
+ return(MAPTYPE);
+ }
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index 0e36a6f..98afaa9 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -103,6 +103,10 @@ entries are used for maps.
+ .B ldap \fPor\fB ldaps
+ The map is stored in an LDAP directory. If \fBldaps\fP is used the
+ appropriate certificate must be configured in the LDAP client.
++.TP
++.B multi
++This map type allows the specification of multiple maps separated
++by "--". These maps are searched in order to resolve key lookups.
+ .RE
+ .TP
+ \fBformat\fP
+diff --git a/modules/lookup_multi.c b/modules/lookup_multi.c
+index 38ca36c..8fa94ae 100644
+--- a/modules/lookup_multi.c
++++ b/modules/lookup_multi.c
+@@ -19,6 +19,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <sys/stat.h>
+
+ #define MODULE_LOOKUP
+ #include "automount.h"
+@@ -28,7 +29,7 @@
+
+ struct module_info {
+ int argc;
+- const char *const *argv;
++ const char **argv;
+ struct lookup_mod *mod;
+ };
+
+@@ -40,11 +41,105 @@ struct lookup_context {
+
+ int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+
++static struct lookup_mod *nss_open_lookup(const char *format, int argc, const char **argv)
++{
++ struct list_head nsslist;
++ struct list_head *head, *p;
++ struct lookup_mod *mod;
++ char buf[MAX_ERR_BUF], *estr;
++
++ if (!argv || !argv[0])
++ return NULL;
++
++ if (*argv[0] == '/')
++ return open_lookup("file", MODPREFIX, format, argc, argv);
++
++ if (!strncmp(argv[0], "file", 4) ||
++ !strncmp(argv[0], "yp", 2) ||
++ !strncmp(argv[0], "nisplus", 7) ||
++ !strncmp(argv[0], "nis", 3) ||
++ !strncmp(argv[0], "ldaps", 5) ||
++ !strncmp(argv[0], "ldap", 4)) {
++ const char *fmt = strchr(argv[0], ',');
++ if (fmt)
++ fmt++;
++ else
++ fmt = format;
++ return open_lookup(argv[0], MODPREFIX, fmt, argc -1, argv + 1);
++ }
++
++ INIT_LIST_HEAD(&nsslist);
++
++ if (nsswitch_parse(&nsslist)) {
++ if (!list_empty(&nsslist))
++ free_sources(&nsslist);
++ error(LOGOPT_ANY, "can't to read name service switch config.");
++ return NULL;
++ }
++
++ head = &nsslist;
++ list_for_each(p, head) {
++ struct nss_source *this;
++
++ this = list_entry(p, struct nss_source, list);
++
++ if (!strcmp(this->source, "files")) {
++ char src_file[] = "file";
++ char src_prog[] = "program";
++ struct stat st;
++ char *type, *path, *save_argv0;
++
++ path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(argv[0]) + 2);
++ if (!path) {
++ estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ crit(LOGOPT_ANY, MODPREFIX "error: %s", estr);
++ free_sources(&nsslist);
++ return NULL;
++ }
++ strcpy(path, AUTOFS_MAP_DIR);
++ strcat(path, "/");
++ strcat(path, argv[0]);
++
++ if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
++ free(path);
++ continue;
++ }
++
++ if (st.st_mode & __S_IEXEC)
++ type = src_prog;
++ else
++ type = src_file;
++
++ save_argv0 = (char *) argv[0];
++ argv[0] = path;
++
++ mod = open_lookup(type, MODPREFIX, format, argc, argv);
++ if (mod) {
++ free_sources(&nsslist);
++ free(save_argv0);
++ return mod;
++ }
++
++ argv[0] = save_argv0;
++ free(path);
++ }
++
++ mod = open_lookup(this->source, MODPREFIX, format, argc, argv);
++ if (mod) {
++ free_sources(&nsslist);
++ return mod;
++ }
++ }
++ free_sources(&nsslist);
++
++ return NULL;
++}
++
+ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void **context)
+ {
+ struct lookup_context *ctxt;
+ char buf[MAX_ERR_BUF];
+- char *map, *mapfmt;
++ char **args;
+ int i, an;
+ char *estr;
+
+@@ -73,39 +168,42 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+
+ memcpy(ctxt->argl, argv, (argc + 1) * sizeof(const char *));
+
++ args = NULL;
+ for (i = an = 0; ctxt->argl[an]; an++) {
+ if (ctxt->m[i].argc == 0) {
+- ctxt->m[i].argv = &ctxt->argl[an];
++ args = (char **) &ctxt->argl[an];
+ }
+ if (!strcmp(ctxt->argl[an], "--")) {
+ ctxt->argl[an] = NULL;
++ if (!args) {
++ crit(LOGOPT_ANY,
++ MODPREFIX "error assigning map args");
++ goto error_out;
++ }
++ ctxt->m[i].argv = copy_argv(ctxt->m[i].argc, (const char **) args);
++ if (!ctxt->m[i].argv)
++ goto nomem;
++ args = NULL;
+ i++;
+ } else {
+ ctxt->m[i].argc++;
+ }
+ }
+
+- for (i = 0; i < ctxt->n; i++) {
+- if (!ctxt->m[i].argv[0]) {
+- crit(LOGOPT_ANY, MODPREFIX "missing module name");
+- goto error_out;
+- }
+- map = strdup(ctxt->m[i].argv[0]);
+- if (!map)
++ /* catch the last one */
++ if (args) {
++ ctxt->m[i].argv = copy_argv(ctxt->m[i].argc, (const char **) args);
++ if (!ctxt->m[i].argv)
+ goto nomem;
++ }
+
+- if ((mapfmt = strchr(map, ',')))
+- *(mapfmt++) = '\0';
+-
+- if (!(ctxt->m[i].mod = open_lookup(map, MODPREFIX,
+- mapfmt ? mapfmt : my_mapfmt,
+- ctxt->m[i].argc - 1,
+- ctxt->m[i].argv + 1))) {
++ for (i = 0; i < ctxt->n; i++) {
++ ctxt->m[i].mod = nss_open_lookup(my_mapfmt,
++ ctxt->m[i].argc, ctxt->m[i].argv);
++ if (!ctxt->m[i].mod) {
+ error(LOGOPT_ANY, MODPREFIX "error opening module");
+- free(map);
+ goto error_out;
+ }
+- free(map);
+ }
+
+ *context = ctxt;
+@@ -116,9 +214,12 @@ nomem:
+ crit(LOGOPT_ANY, MODPREFIX "error: %s", estr);
+ error_out:
+ if (ctxt) {
+- for (i = 0; i < ctxt->n; i++)
++ for (i = 0; i < ctxt->n; i++) {
+ if (ctxt->m[i].mod)
+ close_lookup(ctxt->m[i].mod);
++ if (ctxt->m[i].argv)
++ free_argv(ctxt->m[i].argc, ctxt->m[i].argv);
++ }
+ if (ctxt->m)
+ free(ctxt->m);
+ if (ctxt->argl)
+@@ -188,6 +289,8 @@ int lookup_done(void *context)
+ for (i = 0; i < ctxt->n; i++) {
+ if (ctxt->m[i].mod)
+ rv = rv || close_lookup(ctxt->m[i].mod);
++ if (ctxt->m[i].argv)
++ free_argv(ctxt->m[i].argc, ctxt->m[i].argv);
+ }
+ free(ctxt->argl);
+ free(ctxt->m);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index a9e509d..85af0ad 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -49,6 +49,7 @@
+ - fix incorrect read/write size of startup status token (Matthias Koenig).
+ - fix off-by-one error for lookup of map keys exactly 255 characters long.
+ - improve handling of server not available.
++- fix LDAP_URI server selection.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
+index 18733f3..303b7f2 100644
+--- a/modules/cyrus-sasl.c
++++ b/modules/cyrus-sasl.c
+@@ -75,6 +75,7 @@ static const char *krb5ccval = "MEMORY:_autofstkt";
+ static pthread_mutex_t krb5cc_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static unsigned int krb5cc_in_use = 0;
+
++static unsigned int init_callbacks = 1;
+ static int sasl_log_func(void *, int, const char *);
+ static int getpass_func(sasl_conn_t *, void *, int, sasl_secret_t **);
+ static int getuser_func(void *, int, const char **, unsigned *);
+@@ -386,7 +387,7 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+
+ debug(logopt,
+ "initializing kerberos ticket: client principal %s ",
+- ctxt->client_princ ? "" : "autofsclient");
++ ctxt->client_princ ? ctxt->client_princ : "autofsclient");
+
+ ret = krb5_init_context(&ctxt->krb5ctxt);
+ if (ret) {
+@@ -599,8 +600,8 @@ sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const c
+
+ /* OK and CONTINUE are the only non-fatal return codes here. */
+ if ((result != SASL_OK) && (result != SASL_CONTINUE)) {
+- error(logopt, "sasl_client start failed with error: %s",
+- sasl_errdetail(conn));
++ warn(logopt, "sasl_client_start failed for %s", host);
++ debug(logopt, "sasl_client_start: %s", sasl_errdetail(conn));
+ ldap_memfree(host);
+ sasl_dispose(&conn);
+ return NULL;
+@@ -721,23 +722,30 @@ autofs_sasl_init(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ sasl_conn_t *conn;
+
+ /* Start up Cyrus SASL--only needs to be done once. */
+- if (sasl_client_init(callbacks) != SASL_OK) {
++ if (init_callbacks && sasl_client_init(callbacks) != SASL_OK) {
+ error(logopt, "sasl_client_init failed");
+ return -1;
+ }
++ init_callbacks = 0;
+
+ sasl_auth_id = ctxt->user;
+ sasl_auth_secret = ctxt->secret;
+
+ /*
+- * If sasl_mech was not filled in, it means that there was no
+- * mechanism specified in the configuration file. Try to auto-
+- * select one.
++ * If LDAP_AUTH_AUTODETECT is set, it means that there was no
++ * mechanism specified in the configuration file or auto
++ * selection has been requested, so try to auto-select an
++ * auth mechanism.
+ */
+- if (ctxt->sasl_mech)
++ if (!(ctxt->auth_required & LDAP_AUTH_AUTODETECT))
+ conn = sasl_bind_mech(logopt, ldap, ctxt, ctxt->sasl_mech);
+- else
++ else {
++ if (ctxt->sasl_mech) {
++ free(ctxt->sasl_mech);
++ ctxt->sasl_mech = NULL;
++ }
+ conn = sasl_choose_mech(logopt, ldap, ctxt);
++ }
+
+ if (conn) {
+ sasl_dispose(&conn);
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 7effbf1..93f0477 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -402,8 +402,7 @@ static int do_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ debug(logopt, MODPREFIX "auth_required: %d, sasl_mech %s",
+ ctxt->auth_required, ctxt->sasl_mech);
+
+- if (ctxt->sasl_mech ||
+- (ctxt->auth_required & (LDAP_AUTH_REQUIRED|LDAP_AUTH_AUTODETECT))) {
++ if (ctxt->auth_required & (LDAP_AUTH_REQUIRED|LDAP_AUTH_AUTODETECT)) {
+ rv = autofs_sasl_bind(logopt, ldap, ctxt);
+ debug(logopt, MODPREFIX "autofs_sasl_bind returned %d", rv);
+ } else {
+@@ -497,7 +496,7 @@ static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_c
+ * Determine which authentication mechanism to use if we require
+ * authentication.
+ */
+- if (ctxt->auth_required & LDAP_AUTH_REQUIRED) {
++ if (ctxt->auth_required & (LDAP_AUTH_REQUIRED|LDAP_AUTH_AUTODETECT)) {
+ ldap = auth_init(logopt, uri, ctxt);
+ if (!ldap && ctxt->auth_required & LDAP_AUTH_AUTODETECT)
+ info(logopt,
+@@ -510,6 +509,7 @@ static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_c
+
+ if (!do_bind(logopt, ldap, ctxt)) {
+ unbind_ldap_connection(logopt, ldap, ctxt);
++ autofs_sasl_done(ctxt);
+ error(logopt, MODPREFIX "cannot bind to server");
+ return NULL;
+ }
+@@ -541,6 +541,7 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
+ while(p != ctxt->uri) {
+ this = list_entry(p, struct ldap_uri, list);
+ p = p->next;
++ debug(logopt, "trying server %s", this->uri);
+ ldap = connect_to_server(logopt, this->uri, ctxt);
+ if (ldap) {
+ info(logopt, "connected to uri %s", this->uri);
+@@ -563,22 +564,23 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
+
+ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
+ {
++ struct ldap_uri *this;
+ LDAP *ldap;
+
+ if (ctxt->server || !ctxt->uri) {
+ ldap = do_connect(logopt, ctxt->server, ctxt);
+ return ldap;
+- } else {
+- struct ldap_uri *this;
+- this = list_entry(ctxt->uri->next, struct ldap_uri, list);
+- ldap = do_connect(logopt, this->uri, ctxt);
+- if (ldap)
+- return ldap;
+- /* Failed to connect, put at end of list */
+- list_del_init(&this->list);
+- list_add_tail(&this->list, ctxt->uri);
+ }
+
++ this = list_entry(ctxt->uri->next, struct ldap_uri, list);
++ ldap = do_connect(logopt, this->uri, ctxt);
++ if (ldap)
++ return ldap;
++
++ /* Failed to connect, put at end of list */
++ list_del_init(&this->list);
++ list_add_tail(&this->list, ctxt->uri);
++
+ #ifdef WITH_SASL
+ autofs_sasl_done(ctxt);
+ #endif
+@@ -844,6 +846,8 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
+ ctxt->tls_required = tls_required;
+ ctxt->auth_required = auth_required;
+ ctxt->sasl_mech = authtype;
++ if (!authtype && (auth_required & LDAP_AUTH_REQUIRED))
++ ctxt->auth_required |= LDAP_AUTH_AUTODETECT;
+ ctxt->user = user;
+ ctxt->secret = secret;
+ ctxt->client_princ = client_princ;
+@@ -886,16 +890,6 @@ static LDAP *auth_init(unsigned logopt, const char *uri, struct lookup_context *
+ int ret;
+ LDAP *ldap;
+
+- /*
+- * First, check to see if a preferred authentication method was
+- * specified by the user. parse_ldap_config will return error
+- * if the permissions on the file were incorrect, or if the
+- * specified authentication type is not valid.
+- */
+- ret = parse_ldap_config(logopt, ctxt);
+- if (ret)
+- return NULL;
+-
+ ldap = init_ldap_connection(logopt, uri, ctxt);
+ if (!ldap)
+ return NULL;
+@@ -909,10 +903,8 @@ static LDAP *auth_init(unsigned logopt, const char *uri, struct lookup_context *
+ * the credential cache and the client and service principals.
+ */
+ ret = autofs_sasl_init(logopt, ldap, ctxt);
+- if (ret) {
+- ctxt->sasl_mech = NULL;
++ if (ret)
+ return NULL;
+- }
+
+ return ldap;
+ }
+@@ -1134,6 +1126,8 @@ static void free_context(struct lookup_context *ctxt)
+ free(ctxt->user);
+ if (ctxt->secret)
+ free(ctxt->secret);
++ if (ctxt->client_princ)
++ free(ctxt->client_princ);
+ if (ctxt->mapname)
+ free(ctxt->mapname);
+ if (ctxt->qdn)
+@@ -1184,6 +1178,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ struct lookup_context *ctxt;
+ char buf[MAX_ERR_BUF];
+ LDAP *ldap = NULL;
++ int ret;
+
+ *context = NULL;
+
+@@ -1224,6 +1219,20 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ }
+ }
+
++#ifdef WITH_SASL
++ /*
++ * First, check to see if a preferred authentication method was
++ * specified by the user. parse_ldap_config will return error
++ * if the permissions on the file were incorrect, or if the
++ * specified authentication type is not valid.
++ */
++ ret = parse_ldap_config(LOGOPT_NONE, ctxt);
++ if (ret) {
++ free_context(ctxt);
++ return 1;
++ }
++#endif
++
+ if (ctxt->server || !ctxt->uri) {
+ ldap = connect_to_server(LOGOPT_NONE, ctxt->server, ctxt);
+ if (!ldap) {
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 9a2a8c1..933b1a1 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -27,6 +27,7 @@
+ - add SEARCH_BASE configuration option.
+ - work around segv at exit due to libxml2 tsd usage.
+ - re-read config on HUP signal.
++- add LDAP_URI, LDAP_TIMEOUT and LDAP_NETWORK_TIMEOUT configuration options.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/include/defaults.h b/include/defaults.h
+index 0984b1c..46393d9 100644
+--- a/include/defaults.h
++++ b/include/defaults.h
+@@ -26,7 +26,8 @@
+ #define DEFAULT_BROWSE_MODE 1
+ #define DEFAULT_LOGGING 0
+
+-#define DEFAULT_LDAP_SERVER NULL
++#define DEFAULT_LDAP_TIMEOUT -1
++#define DEFAULT_LDAP_NETWORK_TIMEOUT 8
+
+ #define DEFAULT_MAP_OBJ_CLASS "nisMap"
+ #define DEFAULT_ENTRY_OBJ_CLASS "nisObject"
+@@ -46,6 +47,10 @@ unsigned int defaults_get_timeout(void);
+ unsigned int defaults_get_browse_mode(void);
+ unsigned int defaults_get_logging(void);
+ const char *defaults_get_ldap_server(void);
++unsigned int defaults_get_ldap_timeout(void);
++unsigned int defaults_get_ldap_network_timeout(void);
++struct list_head *defaults_get_uris(void);
++void defaults_free_uris(struct list_head *);
+ struct ldap_schema *defaults_get_default_schema(void);
+ struct ldap_schema *defaults_get_schema(void);
+ struct ldap_searchdn *defaults_get_searchdns(void);
+diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
+index 1a924be..ca8d658 100644
+--- a/include/lookup_ldap.h
++++ b/include/lookup_ldap.h
+@@ -18,6 +18,11 @@ struct ldap_schema {
+ char *value_attr;
+ };
+
++struct ldap_uri {
++ char *uri;
++ struct list_head list;
++};
++
+ struct ldap_searchdn {
+ char *basedn;
+ struct ldap_searchdn *next;
+@@ -30,6 +35,8 @@ struct lookup_context {
+ int port;
+ char *base;
+ char *qdn;
++ unsigned int timeout;
++ unsigned int network_timeout;
+
+ /* LDAP version 2 or 3 */
+ int version;
+@@ -37,7 +44,17 @@ struct lookup_context {
+ /* LDAP lookup configuration */
+ struct ldap_schema *schema;
+
+- /* List of base dns for searching */
++ /*
++ * List of servers and base dns for searching.
++ * uri is the list of servers to attempt connection to and is
++ * used only if server, above, is NULL. The head of the list
++ * is the server which we are currently connected to.
++ * cur_host tracks chnages to connected server, triggering
++ * a scan of basedns when it changes.
++ * sdns is the list of basdns to check, done in the order
++ * given in configuration.
++ */
++ struct list_head *uri;
+ char *cur_host;
+ struct ldap_searchdn *sdns;
+
+@@ -77,7 +94,7 @@ struct lookup_context {
+ #define LDAP_AUTH_AUTODETECT 0x0004
+
+ /* lookup_ldap.c */
+-LDAP *init_ldap_connection(struct lookup_context *ctxt);
++LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt);
+ int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt);
+ int authtype_requires_creds(const char *authtype);
+
+diff --git a/lib/defaults.c b/lib/defaults.c
+index 7da4631..bf1ceed 100644
+--- a/lib/defaults.c
++++ b/lib/defaults.c
+@@ -17,6 +17,7 @@
+ #include <ctype.h>
+ #include <string.h>
+
++#include "list.h"
+ #include "defaults.h"
+ #include "lookup_ldap.h"
+ #include "log.h"
+@@ -30,7 +31,9 @@
+ #define ENV_NAME_BROWSE_MODE "BROWSE_MODE"
+ #define ENV_NAME_LOGGING "LOGGING"
+
+-#define ENV_LDAP_SERVER "LDAP_SERVER"
++#define LDAP_URI "LDAP_URI"
++#define ENV_LDAP_TIMEOUT "LDAP_TIMEOUT"
++#define ENV_LDAP_NETWORK_TIMEOUT "LDAP_NETWORK_TIMEOUT"
+
+ #define SEARCH_BASE "SEARCH_BASE"
+
+@@ -44,7 +47,6 @@
+ #define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE"
+
+ static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME;
+-static const char *default_ldap_server = DEFAULT_LDAP_SERVER;
+ static const char *default_auth_conf_file = DEFAULT_AUTH_CONF_FILE;
+
+ static char *get_env_string(const char *name)
+@@ -178,6 +180,99 @@ static int parse_line(char *line, char **res, char **value)
+ return 1;
+ }
+
++void defaults_free_uris(struct list_head *list)
++{
++ struct list_head *next;
++ struct ldap_uri *uri;
++
++ if (list_empty(list)) {
++ free(list);
++ return;
++ }
++
++ next = list->next;
++ while (next != list) {
++ uri = list_entry(next, struct ldap_uri, list);
++ next = next->next;
++ list_del(&uri->list);
++ free(uri->uri);
++ free(uri);
++ }
++ free(list);
++
++ return;
++}
++
++static unsigned int add_uris(char *value, struct list_head *list)
++{
++ char *str, *tok, *ptr = NULL;
++ size_t len = strlen(value);
++
++ str = alloca(len);
++ if (!str)
++ return 0;
++ strcpy(str, value);
++
++ tok = strtok_r(str, " ", &ptr);
++ while (tok) {
++ struct ldap_uri *new;
++ char *uri;
++
++ new = malloc(sizeof(struct ldap_uri));
++ if (!new)
++ continue;
++
++ uri = strdup(tok);
++ if (!uri)
++ free(new);
++ else {
++ new->uri = uri;
++ list_add_tail(&new->list, list);
++ }
++
++ tok = strtok_r(NULL, " ", &ptr);
++ }
++
++ return 1;
++}
++
++struct list_head *defaults_get_uris(void)
++{
++ FILE *f;
++ char buf[MAX_LINE_LEN];
++ char *res;
++ struct list_head *list;
++
++ f = fopen(DEFAULTS_CONFIG_FILE, "r");
++ if (!f)
++ return NULL;
++
++ list = malloc(sizeof(struct list_head));
++ if (!list) {
++ fclose(f);
++ return NULL;
++ }
++ INIT_LIST_HEAD(list);
++
++ while ((res = fgets(buf, MAX_LINE_LEN, f))) {
++ char *key, *value;
++
++ if (!parse_line(res, &key, &value))
++ continue;
++
++ if (!strcasecmp(res, LDAP_URI))
++ add_uris(value, list);
++ }
++
++ if (list_empty(list)) {
++ free(list);
++ list = NULL;
++ }
++
++ fclose(f);
++ return list;
++}
++
+ /*
+ * Read config env variables and check they have been set.
+ *
+@@ -205,7 +300,8 @@ unsigned int defaults_read_config(void)
+ check_set_config_value(key, ENV_NAME_TIMEOUT, value) ||
+ check_set_config_value(key, ENV_NAME_BROWSE_MODE, value) ||
+ check_set_config_value(key, ENV_NAME_LOGGING, value) ||
+- check_set_config_value(key, ENV_LDAP_SERVER, value) ||
++ check_set_config_value(key, ENV_LDAP_TIMEOUT, value) ||
++ check_set_config_value(key, ENV_LDAP_NETWORK_TIMEOUT, value) ||
+ check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value) ||
+ check_set_config_value(key, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
+ check_set_config_value(key, ENV_NAME_MAP_ATTR, value) ||
+@@ -284,15 +380,26 @@ unsigned int defaults_get_logging(void)
+ return logging;
+ }
+
+-const char *defaults_get_ldap_server(void)
++unsigned int defaults_get_ldap_timeout(void)
+ {
+- char *server;
++ int res;
+
+- server = get_env_string(ENV_LDAP_SERVER);
+- if (!server)
+- return default_ldap_server;
++ res = get_env_number(ENV_LDAP_TIMEOUT);
++ if (res < 0)
++ res = DEFAULT_LDAP_TIMEOUT;
+
+- return (const char *) server;
++ return res;
++}
++
++unsigned int defaults_get_ldap_network_timeout(void)
++{
++ int res;
++
++ res = get_env_number(ENV_LDAP_NETWORK_TIMEOUT);
++ if (res < 0)
++ res = DEFAULT_LDAP_NETWORK_TIMEOUT;
++
++ return res;
+ }
+
+ struct ldap_schema *defaults_get_default_schema(void)
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index 0cb2f07..68447e0 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -230,10 +230,27 @@ values must be set, any partial schema specification will be ignored.
+ .P
+ The configuration settings available are:
+ .TP
++.B LDAP_TIMEOUT
++Set the network response timeout (default 8).
++Set timeout value for the synchronous API calls. The default is the LDAP
++library default of an infinite timeout.
++.TP
++.B LDAP_NETWORK_TIMEOUT
++Set the network response timeout (default 8).
++.TP
++.B LDAP_URI
++A space seperated list of server uris of the form <proto>://<server>[/]
++where <proto> can be ldap or ldaps. The option can be given multiple times.
++Map entries that include a server name override this option and it is then
++not used. Default is an empty list in which case either the server given
++in a map entry or the LDAP configured default is used. This uri list is read at
++startup and whenever the daemon receives a HUP signal.
++.TP
+ .B SEARCH_BASE
+ The base dn to use when searching for amap base dn. This entry may be
+ given multiple times and each will be checked for a map base dn in
+-the order they occur in the configuration.
++the order they occur in the configuration. The search base list is read
++at startup and whenever the daemon recieves a HUP signal.
+ .TP
+ .B MAP_OBJECT_CLASS
+ The map object class. In the \fBnisMap\fP schema this corresponds to the class
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 2baf8b8..4068561 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -49,6 +49,8 @@ static struct ldap_schema common_schema[] = {
+ };
+ static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema);
+
++static LDAP *auth_init(const char *, struct lookup_context *);
++
+ int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
+ {
+ int rv;
+@@ -59,10 +61,18 @@ int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
+ rv = ldap_simple_bind_s(ldap, NULL, NULL);
+
+ if (rv != LDAP_SUCCESS) {
+- crit(LOGOPT_ANY,
+- MODPREFIX "Unable to bind to the LDAP server: "
+- "%s, error %s", ctxt->server ? "" : "(default)",
+- ldap_err2string(rv));
++ if (!ctxt->uri) {
++ crit(LOGOPT_ANY,
++ MODPREFIX "Unable to bind to the LDAP server: "
++ "%s, error %s", ctxt->server ? "" : "(default)",
++ ldap_err2string(rv));
++ } else {
++ struct ldap_uri *uri;
++ uri = list_entry(ctxt->uri->next, struct ldap_uri, list);
++ warn(LOGOPT_ANY,
++ MODPREFIX "Unable to bind to the LDAP server: "
++ "%s, error %s", uri->uri, ldap_err2string(rv));
++ }
+ return -1;
+ }
+
+@@ -98,20 +108,21 @@ int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt)
+ return rv;
+ }
+
+-LDAP *init_ldap_connection(struct lookup_context *ctxt)
++LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
+ {
+ LDAP *ldap = NULL;
+- int timeout = 8;
++ struct timeval timeout = { ctxt->timeout, 0 };
++ struct timeval net_timeout = { ctxt->network_timeout, 0 };
+ int rv;
+
+ ctxt->version = 3;
+
+ /* Initialize the LDAP context. */
+- rv = ldap_initialize(&ldap, ctxt->server);
++ rv = ldap_initialize(&ldap, uri);
+ if (rv != LDAP_OPT_SUCCESS) {
+ crit(LOGOPT_ANY,
+ MODPREFIX "couldn't initialize LDAP connection to %s",
+- ctxt->server ? ctxt->server : "default server");
++ uri ? uri : "default server");
+ return NULL;
+ }
+
+@@ -120,7 +131,7 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
+ if (rv != LDAP_OPT_SUCCESS) {
+ /* fall back to LDAPv2 */
+ ldap_unbind_ext(ldap, NULL, NULL);
+- rv = ldap_initialize(&ldap, ctxt->server);
++ rv = ldap_initialize(&ldap, uri);
+ if (rv != LDAP_OPT_SUCCESS) {
+ crit(LOGOPT_ANY, MODPREFIX "couldn't initialize LDAP");
+ return NULL;
+@@ -128,12 +139,22 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
+ ctxt->version = 2;
+ }
+
+- /* Sane network connection timeout */
+- rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
++
++ if (ctxt->timeout != -1) {
++ /* Set synchronous call timeout */
++ rv = ldap_set_option(ldap, LDAP_OPT_TIMEOUT, &timeout);
++ if (rv != LDAP_OPT_SUCCESS)
++ info(LOGOPT_ANY, MODPREFIX
++ "failed to set synchronous call timeout to %d",
++ timeout.tv_sec);
++ }
++
++ /* Sane network timeout */
++ rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &net_timeout);
+ if (rv != LDAP_OPT_SUCCESS)
+ info(LOGOPT_ANY,
+ MODPREFIX "failed to set connection timeout to %d",
+- timeout);
++ net_timeout.tv_sec);
+
+ #ifdef WITH_SASL
+ if (ctxt->use_tls) {
+@@ -159,7 +180,7 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
+ return NULL;
+ }
+ ctxt->use_tls = LDAP_TLS_DONT_USE;
+- ldap = init_ldap_connection(ctxt);
++ ldap = init_ldap_connection(uri, ctxt);
+ if (ldap)
+ ctxt->use_tls = LDAP_TLS_INIT;
+ return ldap;
+@@ -271,7 +292,7 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ e = ldap_first_entry(ldap, result);
+ if (e) {
+ dn = ldap_get_dn(ldap, e);
+- debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
++ debug(LOGOPT_NONE, MODPREFIX "found query dn %s", dn);
+ } else {
+ debug(LOGOPT_NONE,
+ MODPREFIX "query succeeded, no matches for %s",
+@@ -378,16 +399,11 @@ static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
+ return 0;
+ }
+
+-static LDAP *do_connect(struct lookup_context *ctxt)
++static int do_bind(LDAP *ldap, struct lookup_context *ctxt)
+ {
+- LDAP *ldap;
+ char *host = NULL, *nhost;
+ int rv, need_base = 1;
+
+- ldap = init_ldap_connection(ctxt);
+- if (!ldap)
+- return NULL;
+-
+ #ifdef WITH_SASL
+ debug(LOGOPT_NONE, "auth_required: %d, sasl_mech %s",
+ ctxt->auth_required, ctxt->sasl_mech);
+@@ -407,23 +423,19 @@ static LDAP *do_connect(struct lookup_context *ctxt)
+ debug(LOGOPT_NONE, MODPREFIX "ldap anonymous bind returned %d", rv);
+ #endif
+
+- if (rv != 0) {
+- unbind_ldap_connection(ldap, ctxt);
+- return NULL;
+- }
++ if (rv != 0)
++ return 0;
+
+ rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
+ if (rv != LDAP_SUCCESS || !host) {
+- unbind_ldap_connection(ldap, ctxt);
+ debug(LOGOPT_ANY, "failed to get hostname for connection");
+- return NULL;
++ return 0;
+ }
+
+ nhost = strdup(host);
+ if (!nhost) {
+- unbind_ldap_connection(ldap, ctxt);
+ debug(LOGOPT_ANY, "failed to alloc context for hostname");
+- return NULL;
++ return 0;
+ }
+ ldap_memfree(host);
+
+@@ -443,7 +455,7 @@ static LDAP *do_connect(struct lookup_context *ctxt)
+ }
+
+ if (!need_base)
+- return ldap;
++ return 1;
+
+ /*
+ * If the schema isn't defined in the configuration then check for
+@@ -452,20 +464,134 @@ static LDAP *do_connect(struct lookup_context *ctxt)
+ */
+ if (!ctxt->schema) {
+ if (!find_query_dn(ldap, ctxt)) {
+- unbind_ldap_connection(ldap, ctxt);
+ error(LOGOPT_ANY,
+ MODPREFIX "failed to find valid query dn");
+- return NULL;
++ return 0;
+ }
+ } else {
+ const char *class = ctxt->schema->map_class;
+ const char *key = ctxt->schema->map_attr;
+ if (!get_query_dn(ldap, ctxt, class, key)) {
+- unbind_ldap_connection(ldap, ctxt);
+ error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++static LDAP *do_connect(const char *uri, struct lookup_context *ctxt)
++{
++ LDAP *ldap;
++
++ ldap = init_ldap_connection(uri, ctxt);
++ if (!ldap)
++ return NULL;
++
++ if (!do_bind(ldap, ctxt)) {
++ unbind_ldap_connection(ldap, ctxt);
++ return NULL;
++ }
++
++ return ldap;
++}
++
++static LDAP *connect_to_server(const char *uri, struct lookup_context *ctxt)
++{
++ LDAP *ldap;
++
++#ifdef WITH_SASL
++ /*
++ * Determine which authentication mechanism to use if we require
++ * authentication.
++ */
++ if (ctxt->auth_required & LDAP_AUTH_REQUIRED) {
++ ldap = auth_init(uri, ctxt);
++ if (!ldap && ctxt->auth_required & LDAP_AUTH_AUTODETECT)
++ warn(LOGOPT_NONE,
++ "no authentication mechanisms auto detected.");
++ if (!ldap) {
++ error(LOGOPT_ANY, MODPREFIX
++ "cannot initialize authentication setup");
+ return NULL;
+ }
++
++ if (!do_bind(ldap, ctxt)) {
++ unbind_ldap_connection(ldap, ctxt);
++ error(LOGOPT_ANY, MODPREFIX "cannot bind to server");
++ return NULL;
++ }
++
++ return ldap;
++ }
++#endif
++
++ ldap = do_connect(uri, ctxt);
++ if (!ldap) {
++ error(LOGOPT_ANY, MODPREFIX "cannot connect to server");
++ return NULL;
++ }
++
++ return ldap;
++}
++
++static LDAP *find_server(struct lookup_context *ctxt)
++{
++ LDAP *ldap = NULL;
++ struct ldap_uri *this;
++ struct list_head *p;
++ LIST_HEAD(tmp);
++
++ /* Try each uri in list, add connect fails to tmp list */
++ p = ctxt->uri->next;
++ while(p != ctxt->uri) {
++ this = list_entry(p, struct ldap_uri, list);
++ p = p->next;
++ debug(LOGOPT_ANY, "check uri %s", this->uri);
++ ldap = connect_to_server(this->uri, ctxt);
++ if (ldap) {
++ debug(LOGOPT_ANY, "connexted to uri %s", this->uri);
++ break;
++ }
++ list_del_init(&this->list);
++ list_add_tail(&this->list, &tmp);
+ }
++ /*
++ * Successfuly connected uri (head of list) and untried uris are
++ * in ctxt->uri list. Make list of remainder and failed uris with
++ * failed uris at end and assign back to ctxt-uri.
++ */
++ list_splice(ctxt->uri, &tmp);
++ INIT_LIST_HEAD(ctxt->uri);
++ list_splice(&tmp, ctxt->uri);
++
++ return ldap;
++}
++
++static LDAP *do_reconnect(struct lookup_context *ctxt)
++{
++ LDAP *ldap;
++
++ if (ctxt->server || !ctxt->uri) {
++ ldap = do_connect(ctxt->server, ctxt);
++ return ldap;
++ } else {
++ struct ldap_uri *this;
++ this = list_entry(ctxt->uri->next, struct ldap_uri, list);
++ ldap = do_connect(this->uri, ctxt);
++ if (ldap)
++ return ldap;
++ /* Failed to connect, put at end of list */
++ list_del_init(&this->list);
++ list_add_tail(&this->list, ctxt->uri);
++ }
++
++ autofs_sasl_done(ctxt);
++
++ /* Current server failed connect, try the rest */
++ ldap = find_server(ctxt);
++ if (!ldap)
++ error(LOGOPT_ANY, MODPREFIX "failed to find available server");
+
+ return ldap;
+ }
+@@ -760,10 +886,10 @@ out:
+ * information. If there is no configuration file, then we fall back to
+ * trying all supported authentication mechanisms until one works.
+ *
+- * Returns 0 on success, with authtype, user and secret filled in as
+- * appropriate. Returns -1 on failre.
++ * Returns ldap connection on success, with authtype, user and secret
++ * filled in as appropriate. Returns NULL on failre.
+ */
+-int auth_init(struct lookup_context *ctxt)
++static LDAP *auth_init(const char *uri, struct lookup_context *ctxt)
+ {
+ int ret;
+ LDAP *ldap;
+@@ -776,14 +902,11 @@ int auth_init(struct lookup_context *ctxt)
+ */
+ ret = parse_ldap_config(ctxt);
+ if (ret)
+- return -1;
+-
+- if (ctxt->auth_required & LDAP_AUTH_NOTREQUIRED)
+- return 0;
++ return NULL;
+
+- ldap = init_ldap_connection(ctxt);
++ ldap = init_ldap_connection(uri, ctxt);
+ if (!ldap)
+- return -1;
++ return NULL;
+
+ /*
+ * Initialize the sasl library. It is okay if user and secret
+@@ -794,18 +917,12 @@ int auth_init(struct lookup_context *ctxt)
+ * the credential cache and the client and service principals.
+ */
+ ret = autofs_sasl_init(ldap, ctxt);
+- unbind_ldap_connection(ldap, ctxt);
+ if (ret) {
+ ctxt->sasl_mech = NULL;
+- if (ctxt->auth_required & LDAP_AUTH_AUTODETECT) {
+- warn(LOGOPT_NONE,
+- "no authentication mechanisms auto detected.");
+- return 0;
+- }
+- return -1;
++ return NULL;
+ }
+
+- return 0;
++ return ldap;
+ }
+ #endif
+
+@@ -1036,6 +1153,8 @@ static void free_context(struct lookup_context *ctxt)
+ free(ctxt->cur_host);
+ if (ctxt->base)
+ free(ctxt->base);
++ if (ctxt->uri)
++ defaults_free_uris(ctxt->uri);
+ if (ctxt->sdns)
+ defaults_free_searchdns(ctxt->sdns);
+ free(ctxt);
+@@ -1043,6 +1162,30 @@ static void free_context(struct lookup_context *ctxt)
+ return;
+ }
+
++static void validate_uris(struct list_head *list)
++{
++ struct list_head *next;
++
++ next = list->next;
++ while (next != list) {
++ struct ldap_uri *this;
++
++ this = list_entry(next, struct ldap_uri, list);
++ next = next->next;
++
++ /* At least we get some basic validation */
++ if (!ldap_is_ldap_url(this->uri)) {
++ warn(LOGOPT_ANY,
++ "removed invalid uri from list, %s", this->uri);
++ list_del(&this->list);
++ free(this->uri);
++ free(this);
++ }
++ }
++
++ return;
++}
++
+ /*
+ * This initializes a context (persistent non-global data) for queries to
+ * this module. Return zero if we succeed.
+@@ -1051,7 +1194,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ {
+ struct lookup_context *ctxt;
+ char buf[MAX_ERR_BUF];
+- int ret;
+ LDAP *ldap = NULL;
+
+ *context = NULL;
+@@ -1079,33 +1221,42 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ return 1;
+ }
+
+-#ifdef WITH_SASL
+- /*
+- * Determine which authentication mechanism to use. We sanity-
+- * check by binding to the server temporarily.
+- */
+- ret = auth_init(ctxt);
+- if (ret && (ctxt->auth_required & LDAP_AUTH_REQUIRED)) {
+- error(LOGOPT_ANY, MODPREFIX
+- "cannot initialize authentication setup");
+- free_context(ctxt);
+- return 1;
++ ctxt->timeout = defaults_get_ldap_timeout();
++ ctxt->network_timeout = defaults_get_ldap_network_timeout();
++
++ if (!ctxt->server) {
++ struct list_head *uris = defaults_get_uris();
++ if (uris) {
++ validate_uris(uris);
++ if (!list_empty(uris))
++ ctxt->uri = uris;
++ else
++ free(uris);
++ }
+ }
+-#endif
+
+- ldap = do_connect(ctxt);
+- if (!ldap) {
+- error(LOGOPT_ANY, MODPREFIX "cannot connect to server");
+- free_context(ctxt);
+- return 1;
++ if (ctxt->server || !ctxt->uri) {
++ ldap = connect_to_server(ctxt->server, ctxt);
++ if (!ldap) {
++ free_context(ctxt);
++ return 1;
++ }
++ } else {
++ ldap = find_server(ctxt);
++ if (!ldap) {
++ free_context(ctxt);
++ error(LOGOPT_ANY, MODPREFIX
++ "failed to find available server");
++ return 1;
++ }
+ }
+ unbind_ldap_connection(ldap, ctxt);
+
+ /* Open the parser, if we can. */
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parse) {
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
+ free_context(ctxt);
++ crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
+ return 1;
+ }
+ *context = ctxt;
+@@ -1153,7 +1304,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ query[l] = '\0';
+
+ /* Initialize the LDAP context. */
+- ldap = do_connect(ctxt);
++ ldap = do_reconnect(ctxt);
+ if (!ldap)
+ return NSS_STATUS_UNAVAIL;
+
+@@ -1305,7 +1456,7 @@ static int read_one_map(struct autofs_point *ap,
+ query[l] = '\0';
+
+ /* Initialize the LDAP context. */
+- ldap = do_connect(ctxt);
++ ldap = do_reconnect(ctxt);
+ if (!ldap)
+ return NSS_STATUS_UNAVAIL;
+
+@@ -1536,6 +1687,9 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+ if (ret != NSS_STATUS_SUCCESS) {
+ switch (rv) {
+ case LDAP_SIZELIMIT_EXCEEDED:
++ crit(ap->logopt, MODPREFIX
++ "Unable to download entire LDAP map for: %s",
++ ap->path);
+ case LDAP_UNWILLING_TO_PERFORM:
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_UNAVAIL;
+@@ -1612,7 +1766,7 @@ static int lookup_one(struct autofs_point *ap,
+ query[ql] = '\0';
+
+ /* Initialize the LDAP context. */
+- ldap = do_connect(ctxt);
++ ldap = do_reconnect(ctxt);
+ if (!ldap)
+ return CHE_FAIL;
+
+diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
+index 2b1e20a..f01ee5f 100644
+--- a/redhat/autofs.sysconfig.in
++++ b/redhat/autofs.sysconfig.in
+@@ -23,6 +23,25 @@ BROWSE_MODE="no"
+ #
+ # Define base dn for map dn lookup.
+ #
++# Define server URIs
++#
++# LDAP_URI - space seperated list of server uris of the form
++# <proto>://<server>[/] where <proto> can be ldap
++# or ldaps. The option can be given multiple times.
++# Map entries that include a server name override
++# this option.
++#
++#LDAP_URI=""
++#
++# LDAP__TIMEOUT - timeout value for the synchronous API calls
++# (default is LDAP library default).
++#
++#LDAP_TIMEOUT=-1
++#
++# LDAP_NETWORK_TIMEOUT - set the network response timeout (default 8).
++#
++#LDAP_NETWORK_TIMEOUT=8
++#
+ # SEARCH_BASE - base dn to use for searching for map search dn.
+ # Multiple entries can be given and they are checked
+ # in the order they occur here.
+diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
+index 2b1e20a..028341c 100644
+--- a/samples/autofs.conf.default.in
++++ b/samples/autofs.conf.default.in
+@@ -21,6 +21,25 @@ BROWSE_MODE="no"
+ #
+ #LOGGING="none"
+ #
++# Define server URIs
++#
++# LDAP_URI - space seperated list of server uris of the form
++# <proto>://<server>[/] where <proto> can be ldap
++# or ldaps. The option can be given multiple times.
++# Map entries that include a server name override
++# this option.
++#
++#LDAP_URI=""
++#
++# LDAP__TIMEOUT - timeout value for the synchronous API calls
++# (default is LDAP library default).
++#
++#LDAP_TIMEOUT=-1
++#
++# LDAP_NETWORK_TIMEOUT - set the network response timeout (default 8).
++#
++#LDAP_NETWORK_TIMEOUT=8
++#
+ # Define base dn for map dn lookup.
+ #
+ # SEARCH_BASE - base dn to use for searching for map search dn.
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index dd08880..fdd07d1 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -32,6 +32,7 @@
+ - remove unjustified, nasty comment about krb5 package.
+ - fix deadlock in submount mount module.
+ - fix lack of ferror() checking when reading files.
++- fix typo in autofs(5) man page.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/man/autofs.5 b/man/autofs.5
+index eb15c2a..5a01791 100644
+--- a/man/autofs.5
++++ b/man/autofs.5
+@@ -128,7 +128,7 @@ entry looks like this:
+ .RS +.2i
+ .ta 1.0i
+ .nf
+-* server:i/export/home/&
++* server:/export/home/&
+ .fi
+ .RE
+ .sp
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 6931791..91903e9 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -1,6 +1,7 @@
+ ??/??/2007 autofs-5.0.3
+ -----------------------
+ - include krb5.h in lookup_ldap.h (some openssl doesn't implicitly include it).
++- correct initialization of local var in parse_server_string.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 06506a0..de8d515 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -549,7 +549,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ const char *ptr, *name;
+ int l, al_len;
+
+- *proto = '\0';
++ memset(proto, 0, 9);
+ ptr = url;
+
+ debug(LOGOPT_NONE,
+@@ -620,7 +620,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ } else if (strchr(ptr, ':') != NULL) {
+ char *q = NULL;
+
+- /* Isolate the server(s). Include the port spec */
++ /* Isolate the server. Include the port spec */
+ q = strchr(ptr, ':');
+ if (isdigit(*q))
+ while (isdigit(*q))
+@@ -633,7 +633,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ }
+
+ l = q - ptr;
+- if (proto) {
++ if (*proto) {
+ al_len = l + strlen(proto) + 2;
+ tmp = malloc(al_len);
+ } else {
--- /dev/null
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 5450753..36aa785 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -108,8 +108,8 @@ AT_DC ([dD][[cC])
+ AT_O ([oO])
+ AT_C ([cC])
+ DNATTRSTR {AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}
+-DNNAMESTR ([[:alnum:]_.\- ]+)
+-DNNAMETRM (,|{OPTWS}{NL}|{OPTWS}#.*|{OPTWS}\x00)
++DNNAMESTR1 ([[:alnum:]_.\- ]+)
++DNNAMESTR2 ([[:alnum:]_.\-]+)
+
+ INTMAP (-hosts|-null)
+ MULTI ((multi)(,(sun|hesiod))?(:{OPTWS}|{WS}))
+@@ -282,7 +282,12 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ return EQUAL;
+ }
+
+- {DNNAMESTR}/{DNNAMETRM} {
++ {DNNAMESTR1}/"," {
++ strcpy(master_lval.strtype, master_text);
++ return DNNAME;
++ }
++
++ {DNNAMESTR2} {
+ strcpy(master_lval.strtype, master_text);
+ return DNNAME;
+ }
--- /dev/null
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 48bc233..5450753 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -108,8 +108,8 @@ AT_DC ([dD][[cC])
+ AT_O ([oO])
+ AT_C ([cC])
+ DNATTRSTR {AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}
+-DNNAMESTR ([[:alnum:]_.\-]+)
+-DNNAMETRM (,|{WS}{NL}|{WS}#.*|\x00)
++DNNAMESTR ([[:alnum:]_.\- ]+)
++DNNAMETRM (,|{OPTWS}{NL}|{OPTWS}#.*|{OPTWS}\x00)
+
+ INTMAP (-hosts|-null)
+ MULTI ((multi)(,(sun|hesiod))?(:{OPTWS}|{WS}))
+@@ -379,7 +379,13 @@ void master_set_scan_buffer(const char *buffer)
+ {
+ line = buffer;
+ line_pos = &line[0];
+- line_lim = line + strlen(buffer);
++ /*
++ * Ensure buffer is 1 greater than string and is zeroed before
++ * the parse so we can fit the extra NULL which allows us to
++ * explicitly match an end of line within the buffer (ie. the
++ * need for 2 NULLS when parsing in memeory buffers).
++ */
++ line_lim = line + strlen(buffer) + 1;
+ }
+
+ #define min(a,b) (((a) < (b)) ? (a) : (b))
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index 921b32b..c093415 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -479,7 +479,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+
+ master->name = save_name;
+ } else {
+- blen = path_len + 1 + ent_len + 1;
++ blen = path_len + 1 + ent_len + 2;
+ buffer = malloc(blen);
+ if (!buffer) {
+ error(logopt,
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 00215af..dfb3054 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -1368,7 +1368,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ goto next;
+ }
+
+- blen = strlen(*keyValue) + 1 + strlen(*values) + 1;
++ blen = strlen(*keyValue) + 1 + strlen(*values) + 2;
+ if (blen > PARSE_MAX_BUF) {
+ error(logopt, MODPREFIX "map entry too long");
+ ldap_value_free(values);
+diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
+index ff8bd49..bcdaeeb 100644
+--- a/modules/lookup_nisplus.c
++++ b/modules/lookup_nisplus.c
+@@ -90,7 +90,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ char *path, *ent;
+ char *buffer;
+ char buf[MAX_ERR_BUF];
+- int cur_state;
++ int cur_state, len;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ tablename = alloca(strlen(ctxt->mapname) + strlen(ctxt->domainname) + 20);
+@@ -138,11 +138,13 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+
+ ent = ENTRY_VAL(this, 1);
+
+- buffer = malloc(ENTRY_LEN(this, 0) + 1 + ENTRY_LEN(this, 1) + 1);
++ len = ENTRY_LEN(this, 0) + 1 + ENTRY_LEN(this, 1) + 2;
++ buffer = malloc(len);
+ if (!buffer) {
+ logerr(MODPREFIX "could not malloc parse buffer");
+ continue;
+ }
++ memset(buffer, 0, len);
+
+ strcat(buffer, path);
+ strcat(buffer, " ");
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index 63fc8e3..7ba6940 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -178,7 +178,7 @@ int yp_all_master_callback(int status, char *ypkey, int ypkeylen,
+ *(ypkey + ypkeylen) = '\0';
+ *(val + vallen) = '\0';
+
+- len = ypkeylen + 1 + vallen + 1;
++ len = ypkeylen + 1 + vallen + 2;
+
+ buffer = alloca(len);
+ if (!buffer) {
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index ca290f9..5e3a9ec 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -38,6 +38,7 @@
+ - add dynamic logging (adapted from v4 patch from Jeff Moyer).
+ - fix recursive loopback mounts (Matthias Koenig).
+ - add map re-load to verbose logging.
++- fix handling of LDAP base dns with spaces.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 00cd223..48bc233 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -109,6 +109,7 @@ AT_O ([oO])
+ AT_C ([cC])
+ DNATTRSTR {AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}
+ DNNAMESTR ([[:alnum:]_.\-]+)
++DNNAMETRM (,|{WS}{NL}|{WS}#.*|\x00)
+
+ INTMAP (-hosts|-null)
+ MULTI ((multi)(,(sun|hesiod))?(:{OPTWS}|{WS}))
+@@ -281,7 +282,7 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ return EQUAL;
+ }
+
+- {DNNAMESTR} {
++ {DNNAMESTR}/{DNNAMETRM} {
+ strcpy(master_lval.strtype, master_text);
+ return DNNAME;
+ }
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 795ec30..1c147c5 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -40,6 +40,7 @@
+ - add map re-load to verbose logging.
+ - fix handling of LDAP base dns with spaces.
+ - handle MTAB_NOTUPDATED status return from mount.
++- when default master map, auto.master, is used also check for auto_master.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index fd99cf2..0be10d3 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -222,6 +222,28 @@ int lookup_nss_read_master(struct master *master, time_t age)
+ "reading master %s %s", this->source, master->name);
+
+ result = read_master_map(master, this->source, age);
++
++ /*
++ * If the name of the master map hasn't been explicitly
++ * configured and we're not reading an included master map
++ * then we're using auto.master as the default. Many setups
++ * also use auto_master as the default master map so we
++ * check for this map when auto.master isn't found.
++ */
++ if (result != NSS_STATUS_SUCCESS &&
++ !master->depth && !defaults_master_set()) {
++ char *tmp = strchr(master->name, '.');
++ if (tmp) {
++ debug(logopt,
++ "%s not found, replacing '.' with '_'",
++ master->name);
++ *tmp = '_';
++ result = read_master_map(master, this->source, age);
++ if (result != NSS_STATUS_SUCCESS)
++ *tmp = '.';
++ }
++ }
++
+ if (result == NSS_STATUS_UNKNOWN) {
+ debug(logopt, "no map - continuing to next source");
+ continue;
+diff --git a/include/defaults.h b/include/defaults.h
+index 0e0e2a5..e296478 100644
+--- a/include/defaults.h
++++ b/include/defaults.h
+@@ -43,6 +43,7 @@ struct ldap_searchdn;
+
+ unsigned int defaults_read_config(unsigned int);
+ const char *defaults_get_master_map(void);
++int defaults_master_set(void);
+ unsigned int defaults_get_timeout(void);
+ unsigned int defaults_get_browse_mode(void);
+ unsigned int defaults_get_logging(void);
+diff --git a/lib/defaults.c b/lib/defaults.c
+index 94885e8..f494103 100644
+--- a/lib/defaults.c
++++ b/lib/defaults.c
+@@ -350,6 +350,15 @@ const char *defaults_get_master_map(void)
+ return (const char *) master;
+ }
+
++int defaults_master_set(void)
++{
++ char *val = getenv(ENV_NAME_MASTER_MAP);
++ if (!val)
++ return 0;
++
++ return 1;
++}
++
+ unsigned int defaults_get_timeout(void)
+ {
+ long timeout;
--- /dev/null
+diff --git a/daemon/spawn.c b/daemon/spawn.c
+index 0ed873e..78d69c6 100644
+--- a/daemon/spawn.c
++++ b/daemon/spawn.c
+@@ -25,6 +25,7 @@
+ #include <time.h>
+ #include <sys/wait.h>
+ #include <sys/stat.h>
++#include <sys/mount.h>
+
+ #include "automount.h"
+
+@@ -308,6 +309,8 @@ int spawn_mount(unsigned logopt, ...)
+ while (retries--) {
+ ret = do_spawn(logopt, options, prog, (const char **) argv);
+ if (ret & MTAB_NOTUPDATED) {
++ struct timespec tm = {3, 0};
++
+ /*
+ * If the mount succeeded but the mtab was not
+ * updated, then retry the mount with the -f (fake)
+@@ -329,6 +332,9 @@ int spawn_mount(unsigned logopt, ...)
+ argv[argc - 1] = argv[argc - 2];
+ argv[argc - 2] = arg_fake;
+ }
++
++ nanosleep(&tm, NULL);
++
+ continue;
+ }
+ break;
+@@ -336,9 +342,16 @@ int spawn_mount(unsigned logopt, ...)
+
+ /* This is not a fatal error */
+ if (ret == MTAB_NOTUPDATED) {
+- warn(logopt, "Unable to update the mtab file, /proc/mounts "
+- "and /etc/mtab will differ");
+- ret = 0;
++ /*
++ * Version 5 requires that /etc/mtab be in sync with
++ * /proc/mounts. If we're unable to update matb after
++ * retrying then we have no choice but umount the mount
++ * and return a fail.
++ */
++ warn(logopt,
++ "Unable to update the mtab file, forcing mount fail!");
++ umount(argv[argc]);
++ ret = MNT_FORCE_FAIL;
+ }
+
+ return ret;
+@@ -395,6 +408,8 @@ int spawn_bind_mount(unsigned logopt, ...)
+ while (retries--) {
+ ret = do_spawn(logopt, options, prog, (const char **) argv);
+ if (ret & MTAB_NOTUPDATED) {
++ struct timespec tm = {3, 0};
++
+ /*
+ * If the mount succeeded but the mtab was not
+ * updated, then retry the mount with the -f (fake)
+@@ -416,6 +431,9 @@ int spawn_bind_mount(unsigned logopt, ...)
+ argv[argc - 1] = argv[argc - 2];
+ argv[argc - 2] = arg_fake;
+ }
++
++ nanosleep(&tm, NULL);
++
+ continue;
+ }
+ break;
+@@ -423,9 +441,16 @@ int spawn_bind_mount(unsigned logopt, ...)
+
+ /* This is not a fatal error */
+ if (ret == MTAB_NOTUPDATED) {
+- warn(logopt, "Unable to update the mtab file, /proc/mounts "
+- "and /etc/mtab will differ");
+- ret = 0;
++ /*
++ * Version 5 requires that /etc/mtab be in sync with
++ * /proc/mounts. If we're unable to update matb after
++ * retrying then we have no choice but umount the mount
++ * and return a fail.
++ */
++ warn(logopt,
++ "Unable to update the mtab file, forcing mount fail!");
++ umount(argv[argc]);
++ ret = MNT_FORCE_FAIL;
+ }
+
+ return ret;
+diff --git a/include/automount.h b/include/automount.h
+index 4887da6..fa5cd97 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -78,6 +78,7 @@ int load_autofs4_module(void);
+ #define MOUNTED_LOCK _PATH_MOUNTED "~" /* mounts' lock file */
+ #define MTAB_NOTUPDATED 0x1000 /* mtab succeded but not updated */
+ #define NOT_MOUNTED 0x0100 /* path notmounted */
++#define MNT_FORCE_FAIL -1
+ #define _PROC_MOUNTS "/proc/mounts"
+
+ /* Constants for lookup modules */
+diff --git a/modules/mount_bind.c b/modules/mount_bind.c
+index 04284f5..ef973e1 100644
+--- a/modules/mount_bind.c
++++ b/modules/mount_bind.c
+@@ -147,7 +147,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ if ((!ap->ghost && name_len) || !existed)
+ rmdir_path(ap, fullpath, ap->dev);
+
+- return 1;
++ return err;
+ } else {
+ debug(ap->logopt,
+ MODPREFIX "mounted %s type %s on %s",
+diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
+index bad21fc..0e7aebe 100644
+--- a/modules/mount_nfs.c
++++ b/modules/mount_nfs.c
+@@ -233,6 +233,10 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ return 0;
+ }
+
++ /* Failed to update mtab, don't try any more */
++ if (err == MNT_FORCE_FAIL)
++ goto forced_fail;
++
+ /* No hostname, can't be NFS */
+ if (!this->name) {
+ this = this->next;
+@@ -275,6 +279,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ this = this->next;
+ }
+
++forced_fail:
+ free_host_list(&hosts);
+ ap->ghost = save_ghost;
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 5e3a9ec..795ec30 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -39,6 +39,7 @@
+ - fix recursive loopback mounts (Matthias Koenig).
+ - add map re-load to verbose logging.
+ - fix handling of LDAP base dns with spaces.
++- handle MTAB_NOTUPDATED status return from mount.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/spawn.c b/daemon/spawn.c
+index ab3274c..0ed873e 100644
+--- a/daemon/spawn.c
++++ b/daemon/spawn.c
+@@ -268,9 +268,11 @@ int spawn_mount(unsigned logopt, ...)
+ char **argv, **p;
+ char prog[] = PATH_MOUNT;
+ char arg0[] = PATH_MOUNT;
++ /* In case we need to use the fake option to mount */
++ char arg_fake[] = "-f";
+ unsigned int options;
+ unsigned int retries = MTAB_LOCK_RETRIES;
+- int ret;
++ int ret, printed = 0;
+
+ /* If we use mount locking we can't validate the location */
+ #ifdef ENABLE_MOUNT_LOCKING
+@@ -283,7 +285,8 @@ int spawn_mount(unsigned logopt, ...)
+ for (argc = 1; va_arg(arg, char *); argc++);
+ va_end(arg);
+
+- if (!(argv = alloca(sizeof(char *) * argc + 1)))
++ /* Alloc 1 extra slot in case we need to use the "-f" option */
++ if (!(argv = alloca(sizeof(char *) * argc + 2)))
+ return -1;
+
+ argv[0] = arg0;
+@@ -304,11 +307,40 @@ int spawn_mount(unsigned logopt, ...)
+
+ while (retries--) {
+ ret = do_spawn(logopt, options, prog, (const char **) argv);
+- if (ret & MTAB_NOTUPDATED)
++ if (ret & MTAB_NOTUPDATED) {
++ /*
++ * If the mount succeeded but the mtab was not
++ * updated, then retry the mount with the -f (fake)
++ * option to just update the mtab.
++ */
++ if (!printed) {
++ debug(logopt, "mount failed with error code 16"
++ ", retrying with the -f option");
++ printed = 1;
++ }
++
++ /*
++ * Move the last two args so do_spawn() can find the
++ * mount target.
++ */
++ if (!argv[argc]) {
++ argv[argc + 1] = NULL;
++ argv[argc] = argv[argc - 1];
++ argv[argc - 1] = argv[argc - 2];
++ argv[argc - 2] = arg_fake;
++ }
+ continue;
++ }
+ break;
+ }
+
++ /* This is not a fatal error */
++ if (ret == MTAB_NOTUPDATED) {
++ warn(logopt, "Unable to update the mtab file, /proc/mounts "
++ "and /etc/mtab will differ");
++ ret = 0;
++ }
++
+ return ret;
+ }
+
+@@ -328,9 +360,11 @@ int spawn_bind_mount(unsigned logopt, ...)
+ char prog[] = PATH_MOUNT;
+ char arg0[] = PATH_MOUNT;
+ char bind[] = "--bind";
++ /* In case we need to use the fake option to mount */
++ char arg_fake[] = "-f";
+ unsigned int options;
+ unsigned int retries = MTAB_LOCK_RETRIES;
+- int ret;
++ int ret, printed = 0;
+
+ /* If we use mount locking we can't validate the location */
+ #ifdef ENABLE_MOUNT_LOCKING
+@@ -339,8 +373,12 @@ int spawn_bind_mount(unsigned logopt, ...)
+ options = SPAWN_OPT_ACCESS;
+ #endif
+
++ /*
++ * Alloc 2 extra slots, one for the bind option and one in case
++ * we need to use the "-f" option
++ */
+ va_start(arg, logopt);
+- for (argc = 1; va_arg(arg, char *); argc++);
++ for (argc = 2; va_arg(arg, char *); argc++);
+ va_end(arg);
+
+ if (!(argv = alloca(sizeof(char *) * argc + 2)))
+@@ -356,11 +394,40 @@ int spawn_bind_mount(unsigned logopt, ...)
+
+ while (retries--) {
+ ret = do_spawn(logopt, options, prog, (const char **) argv);
+- if (ret & MTAB_NOTUPDATED)
++ if (ret & MTAB_NOTUPDATED) {
++ /*
++ * If the mount succeeded but the mtab was not
++ * updated, then retry the mount with the -f (fake)
++ * option to just update the mtab.
++ */
++ if (!printed) {
++ debug(logopt, "mount failed with error code 16"
++ ", retrying with the -f option");
++ printed = 1;
++ }
++
++ /*
++ * Move the last two args so do_spawn() can find the
++ * mount target.
++ */
++ if (!argv[argc]) {
++ argv[argc + 1] = NULL;
++ argv[argc] = argv[argc - 1];
++ argv[argc - 1] = argv[argc - 2];
++ argv[argc - 2] = arg_fake;
++ }
+ continue;
++ }
+ break;
+ }
+
++ /* This is not a fatal error */
++ if (ret == MTAB_NOTUPDATED) {
++ warn(logopt, "Unable to update the mtab file, /proc/mounts "
++ "and /etc/mtab will differ");
++ ret = 0;
++ }
++
+ return ret;
+ }
+
+@@ -373,7 +440,7 @@ int spawn_umount(unsigned logopt, ...)
+ char arg0[] = PATH_UMOUNT;
+ unsigned int options;
+ unsigned int retries = MTAB_LOCK_RETRIES;
+- int ret;
++ int ret, printed = 0;
+
+ #ifdef ENABLE_MOUNT_LOCKING
+ options = SPAWN_OPT_LOCK;
+@@ -397,9 +464,37 @@ int spawn_umount(unsigned logopt, ...)
+
+ while (retries--) {
+ ret = do_spawn(logopt, options, prog, (const char **) argv);
+- if (ret & MTAB_NOTUPDATED)
+- continue;
+- break;
++ if (ret & MTAB_NOTUPDATED) {
++ /*
++ * If the mount succeeded but the mtab was not
++ * updated, then retry the umount just to update
++ * the mtab.
++ */
++ if (!printed) {
++ debug(logopt, "mount failed with error code 16"
++ ", retrying with the -f option");
++ printed = 1;
++ }
++ } else {
++ /*
++ * umount does not support the "fake" option. Thus,
++ * if we got a return value of MTAB_NOTUPDATED the
++ * first time, that means the umount actually
++ * succeeded. Then, a following umount will fail
++ * due to the fact that nothing was mounted on the
++ * mount point. So, report this as success.
++ */
++ if (retries < MTAB_LOCK_RETRIES - 1)
++ ret = 0;
++ break;
++ }
++ }
++
++ /* This is not a fatal error */
++ if (ret == MTAB_NOTUPDATED) {
++ warn(logopt, "Unable to update the mtab file, /proc/mounts "
++ "and /etc/mtab will differ");
++ ret = 0;
+ }
+
+ return ret;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 0340940..ddfa6f1 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -29,6 +29,7 @@
+ - re-read config on HUP signal.
+ - add LDAP_URI, LDAP_TIMEOUT and LDAP_NETWORK_TIMEOUT configuration options.
+ - fix forground logging and add option to man page.
++- remove unjustified, nasty comment about krb5 package.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 51f6a8b..930b13f 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -1263,22 +1263,6 @@ void *handle_mounts(void *arg)
+ }
+
+ pthread_cleanup_pop(1);
+-
+- /*
+- * A cowboy .. me!
+- * That noise yu ear aint spuurs sonny!!
+- *
+- * The libkrb5support destructor called indirectly through
+- * libgssapi_krb5 which is used bt libkrb5 (somehow) must run
+- * to completion before the last thread using it exits so
+- * that it's per thread data keys are deleted or we get a
+- * little segfault at exit. So much for dlclose being
+- * syncronous.
+- *
+- * So, the solution is a recipe for disaster.
+- * Hope we don't get a really busy system!
+- */
+- /*sleep(1);*/
+ sched_yield();
+
+ return NULL;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index d66b8fc..8df22ae 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -4,6 +4,8 @@
+ - correct initialization of local var in parse_server_string.
+ - add missing "multi" map support.
+ - add multi nsswitch lookup.
++- change random multiple server selection option name to be consistent
++ with existing downstream version 4 naming.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 3e40428..294c511 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -1367,7 +1367,7 @@ static void usage(void)
+ " -d --debug log debuging info\n"
+ " -D --define define global macro variable\n"
+ /*" -f --foreground do not fork into background\n" */
+- " -r --random-replicated-selection\n"
++ " -r --random-multimount-selection\n"
+ " use ramdom replicated server selection\n"
+ " -O --global-options\n"
+ " specify global mount options\n"
+@@ -1469,7 +1469,7 @@ int main(int argc, char *argv[])
+ {"debug", 0, 0, 'd'},
+ {"define", 1, 0, 'D'},
+ {"foreground", 0, 0, 'f'},
+- {"random-selection", 0, 0, 'r'},
++ {"random-multimount-selection", 0, 0, 'r'},
+ {"global-options", 1, 0, 'O'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0}
+diff --git a/man/automount.8 b/man/automount.8
+index b01be83..fc1846a 100644
+--- a/man/automount.8
++++ b/man/automount.8
+@@ -47,7 +47,7 @@ Define a global macro substitution variable. Global definitions
+ are over-ridden macro definitions of the same name specified in
+ mount entries.
+ .TP
+-.I "\-r, \-\-random-replicated-selection"
++.I "\-r, \-\-random-multimount-selection"
+ Enables the use of ramdom selection when choosing a host from a
+ list of replicated servers.
+ .TP
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 9c99966..92013ce 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -18,6 +18,7 @@
+ - add support for the "%" hack for case insensitive attribute schemas.
+ - fix "nosymlink" option handling and add desription to man page.
+ - fix don't fail on empty master map.
++- if there's no "automount" entry in nsswitch.conf use "files" source.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/nss_parse.y b/lib/nss_parse.y
+index 4f67f08..e559696 100644
+--- a/lib/nss_parse.y
++++ b/lib/nss_parse.y
+@@ -45,6 +45,8 @@ struct nss_action act[NSS_STATUS_MAX];
+ #define YYLTYPE_IS_TRIVIAL 0
+ #endif
+
++unsigned int nss_automount_found;
++
+ extern int nss_lineno;
+ extern int nss_lex(void);
+ extern FILE *nss_in;
+@@ -183,10 +185,16 @@ int nsswitch_parse(struct list_head *list)
+
+ nss_in = nsswitch;
+
++ nss_automount_found = 0;
+ nss_list = list;
+ status = nss_parse();
+ nss_list = NULL;
+
++ /* No "automount" nsswitch entry, use "files" */
++ if (!nss_automount_found)
++ if (add_source(list, "files"))
++ status = 0;
++
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+
+diff --git a/lib/nss_tok.l b/lib/nss_tok.l
+index 71d83b0..f96b47f 100644
+--- a/lib/nss_tok.l
++++ b/lib/nss_tok.l
+@@ -56,6 +56,8 @@ int nss_wrap(void);
+ #define YY_MAIN 0
+ #endif
+
++extern unsigned int nss_automount_found;
++
+ %}
+
+ %option nounput
+@@ -85,6 +87,7 @@ other [[:alnum:]@$%^&*()-+_":;?,<>./'{}~`]+
+ %%
+
+ ^{automount}: {
++ nss_automount_found = 1;
+ BEGIN(AUTOMOUNT);
+ }
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 5aee44c..9c99966 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -17,6 +17,7 @@
+ - don't fail on empty master map.
+ - add support for the "%" hack for case insensitive attribute schemas.
+ - fix "nosymlink" option handling and add desription to man page.
++- fix don't fail on empty master map.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 9809b9c..7b79f02 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -61,6 +61,8 @@ static size_t kpkt_len;
+
+ /* Attribute to create detached thread */
+ pthread_attr_t thread_attr;
++/* Attribute to create normal thread */
++pthread_attr_t thread_attr_nodetach;
+
+ struct master_readmap_cond mrc = {
+ PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, NULL, 0, 0, 0, 0};
+@@ -914,7 +916,7 @@ static void *do_notify_state(void *arg)
+ return NULL;
+ }
+
+-static int do_signals(struct master *master, int sig)
++static pthread_t do_signals(struct master *master, int sig)
+ {
+ pthread_t thid;
+ int r_sig = sig;
+@@ -924,7 +926,7 @@ static int do_signals(struct master *master, int sig)
+ if (status)
+ fatal(status);
+
+- status = pthread_create(&thid, &thread_attr, do_notify_state, &r_sig);
++ status = pthread_create(&thid, &thread_attr_nodetach, do_notify_state, &r_sig);
+ if (status) {
+ error(master->default_logging,
+ "mount state notify thread create failed");
+@@ -948,7 +950,7 @@ static int do_signals(struct master *master, int sig)
+
+ pthread_cleanup_pop(1);
+
+- return 1;
++ return thid;
+ }
+
+ static void *do_read_master(void *arg)
+@@ -1038,6 +1040,7 @@ static int do_hup_signal(struct master *master, time_t age)
+ /* Deal with all the signal-driven events in the state machine */
+ static void *statemachine(void *arg)
+ {
++ pthread_t thid = 0;
+ sigset_t signalset;
+ int sig;
+
+@@ -1048,15 +1051,17 @@ static void *statemachine(void *arg)
+ while (1) {
+ sigwait(&signalset, &sig);
+
+-
+- if (master_list_empty(master_list))
+- return NULL;
+-
+ switch (sig) {
+ case SIGTERM:
+ case SIGUSR2:
+ case SIGUSR1:
+- do_signals(master_list, sig);
++ thid = do_signals(master_list, sig);
++ if (thid) {
++ pthread_join(thid, NULL);
++ if (master_list_empty(master_list))
++ return NULL;
++ thid = 0;
++ }
+ break;
+
+ case SIGHUP:
+@@ -1171,10 +1176,6 @@ static void handle_mounts_cleanup(void *arg)
+
+ msg("shut down path %s", path);
+
+- /* If we are the last tell the state machine to shutdown */
+- if (!submount && master_list_empty(master_list))
+- kill(getpid(), SIGTERM);
+-
+ return;
+ }
+
+@@ -1644,6 +1645,14 @@ int main(int argc, char *argv[])
+ }
+ #endif
+
++ if (pthread_attr_init(&thread_attr_nodetach)) {
++ crit(LOGOPT_ANY,
++ "%s: failed to init thread attribute struct!",
++ program);
++ close(start_pipefd[1]);
++ exit(1);
++ }
++
+ msg("Starting automounter version %s, master map %s",
+ version, master_list->name);
+ msg("using kernel protocol version %d.%02d",
+diff --git a/lib/master.c b/lib/master.c
+index 9f24f7e..da05bb6 100644
+--- a/lib/master.c
++++ b/lib/master.c
+@@ -802,7 +802,7 @@ int master_read_master(struct master *master, time_t age, int readall)
+
+ if (list_empty(&master->mounts)) {
+ master_mutex_unlock();
+- error(LOGOPT_ANY, "no mounts in table");
++ warn(LOGOPT_ANY, "no mounts in table");
+ return 1;
+ }
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 20562bd..da8c599 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -14,6 +14,7 @@
+ - fix version passed to get_supported_ver_and_cost.
+ - mark map instances stale so they aren't "cleaned" during updates.
+ - fix large file compile time option.
++- don't fail on empty master map.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/master.c b/lib/master.c
+index 4d31959..9f24f7e 100644
+--- a/lib/master.c
++++ b/lib/master.c
+@@ -803,7 +803,7 @@ int master_read_master(struct master *master, time_t age, int readall)
+ if (list_empty(&master->mounts)) {
+ master_mutex_unlock();
+ error(LOGOPT_ANY, "no mounts in table");
+- return 0;
++ return 1;
+ }
+
+ master_mutex_unlock();
--- /dev/null
+diff --git a/Makefile.conf.in b/Makefile.conf.in
+index ea5fe1d..09c3129 100644
+--- a/Makefile.conf.in
++++ b/Makefile.conf.in
+@@ -71,6 +71,9 @@ autofsconfdir = @confdir@
+ # Location for autofs maps
+ autofsmapdir = @mapdir@
+
++# Location for autofs fifos
++autofsfifodir = @fifodir@
++
+ # Where to install the automount program
+ sbindir = @sbindir@
+
+diff --git a/aclocal.m4 b/aclocal.m4
+index ffeb232..118ef0d 100644
+--- a/aclocal.m4
++++ b/aclocal.m4
+@@ -120,6 +120,22 @@ AC_DEFUN(AF_MAP_D,
+ done
+ fi])
+
++dnl --------------------------------------------------------------------------
++dnl AF_FIFO_D
++dnl
++dnl Check the location of the autofs fifos directory
++dnl --------------------------------------------------------------------------
++AC_DEFUN(AF_FIFO_D,
++[if test -z "$fifodir"; then
++ for fifo_d in /var/run /tmp; do
++ if test -z "$fifodir"; then
++ if test -d "$fifo_d"; then
++ fifodir="$fifo_d"
++ fi
++ fi
++ done
++fi])
++
+ dnl ----------------------------------- ## -*- Autoconf -*-
+ dnl Check if --with-dmalloc was given. ##
+ dnl From Franc,ois Pinard ##
+diff --git a/configure b/configure
+index 3508224..0360086 100755
+--- a/configure
++++ b/configure
+@@ -654,6 +654,7 @@ target_alias
+ initdir
+ confdir
+ mapdir
++fifodir
+ DMALLOCLIB
+ MOUNT
+ HAVE_MOUNT
+@@ -1293,6 +1294,7 @@ Optional Packages:
+ --with-path=PATH look in PATH for binaries needed by the automounter
+ --with-confdir=DIR use DIR for autofs configuration files
+ --with-mapdir=PATH look in PATH for mount maps used by the automounter
++ --with-fifodir=PATH use PATH as the directory for fifos used by the automounter
+ --with-dmalloc use dmalloc, as in
+ http://www.dmalloc.com/dmalloc.tar.gz
+ --with-hesiod=DIR enable Hesiod support (libs and includes in DIR)
+@@ -1844,6 +1846,36 @@ echo "${ECHO_T}$mapdir" >&6; }
+
+
+ #
++# The user can specify --with-fifodir=PATH to specify where autofs fifos go
++#
++if test -z "$fifodir"; then
++ for fifo_d in /var/run /tmp; do
++ if test -z "$fifodir"; then
++ if test -d "$fifo_d"; then
++ fifodir="$fifo_d"
++ fi
++ fi
++ done
++fi
++
++# Check whether --with-fifodir was given.
++if test "${with_fifodir+set}" = set; then
++ withval=$with_fifodir; if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no"
++ then
++ :
++ else
++ fifodir="${withval}"
++ fi
++
++fi
++
++{ echo "$as_me:$LINENO: checking for autofs fifos directory" >&5
++echo $ECHO_N "checking for autofs fifos directory... $ECHO_C" >&6; }
++{ echo "$as_me:$LINENO: result: $fifodir" >&5
++echo "${ECHO_T}$fifodir" >&6; }
++
++
++#
+ # Optional include dmalloc
+ #
+ { echo "$as_me:$LINENO: checking if malloc debugging is wanted" >&5
+@@ -6074,6 +6106,7 @@ target_alias!$target_alias$ac_delim
+ initdir!$initdir$ac_delim
+ confdir!$confdir$ac_delim
+ mapdir!$mapdir$ac_delim
++fifodir!$fifodir$ac_delim
+ DMALLOCLIB!$DMALLOCLIB$ac_delim
+ MOUNT!$MOUNT$ac_delim
+ HAVE_MOUNT!$HAVE_MOUNT$ac_delim
+@@ -6124,7 +6157,7 @@ LIBOBJS!$LIBOBJS$ac_delim
+ LTLIBOBJS!$LTLIBOBJS$ac_delim
+ _ACEOF
+
+- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 88; then
++ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then
+ break
+ elif $ac_last_try; then
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+diff --git a/configure.in b/configure.in
+index 8cddf90..a83b3f1 100644
+--- a/configure.in
++++ b/configure.in
+@@ -79,6 +79,23 @@ AC_MSG_RESULT([$mapdir])
+ AC_SUBST(mapdir)
+
+ #
++# The user can specify --with-fifodir=PATH to specify where autofs fifos go
++#
++AF_FIFO_D()
++AC_ARG_WITH(fifodir,
++[ --with-fifodir=PATH use PATH as the directory for fifos used by the automounter],
++ if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no"
++ then
++ :
++ else
++ fifodir="${withval}"
++ fi
++)
++AC_MSG_CHECKING([for autofs fifos directory])
++AC_MSG_RESULT([$fifodir])
++AC_SUBST(fifodir)
++
++#
+ # Optional include dmalloc
+ #
+ AM_WITH_DMALLOC()
+diff --git a/daemon/Makefile b/daemon/Makefile
+index 4ee70eb..528a684 100644
+--- a/daemon/Makefile
++++ b/daemon/Makefile
+@@ -16,6 +16,7 @@ CFLAGS += -rdynamic $(DAEMON_CFLAGS) -D_GNU_SOURCE -I../include
+ CFLAGS += -DAUTOFS_LIB_DIR=\"$(autofslibdir)\"
+ CFLAGS += -DAUTOFS_MAP_DIR=\"$(autofsmapdir)\"
+ CFLAGS += -DAUTOFS_CONF_DIR=\"$(autofsconfdir)\"
++CFLAGS += -DAUTOFS_FIFO_DIR=\"$(autofsfifodir)\"
+ CFLAGS += -DVERSION_STRING=\"$(version)\"
+ LDFLAGS += -rdynamic
+ LIBS = -ldl
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 7e7d1e6..a12b6da 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -50,6 +50,9 @@ const char *libdir = AUTOFS_LIB_DIR; /* Location of library modules */
+ const char *mapdir = AUTOFS_MAP_DIR; /* Location of mount maps */
+ const char *confdir = AUTOFS_CONF_DIR; /* Location of autofs config file */
+
++/* autofs fifo name prefix */
++const char *fifodir = AUTOFS_FIFO_DIR "/autofs.fifo";
++
+ const char *global_options; /* Global option, from command line */
+
+ static char *pid_file = NULL; /* File in which to keep pid */
+@@ -650,14 +653,13 @@ static int fullread(int fd, void *ptr, size_t len)
+ static char *automount_path_to_fifo(unsigned logopt, const char *path)
+ {
+ char *fifo_name, *p;
+- int name_len = strlen(path) + strlen(AUTOFS_LOGPRI_FIFO) + 1;
++ int name_len = strlen(path) + strlen(fifodir) + 1;
+ int ret;
+
+ fifo_name = malloc(name_len);
+ if (!fifo_name)
+ return NULL;
+- ret = snprintf(fifo_name, name_len, "%s%s",
+- AUTOFS_LOGPRI_FIFO, path);
++ ret = snprintf(fifo_name, name_len, "%s%s", fifodir, path);
+ if (ret >= name_len) {
+ info(logopt,
+ "fifo path for \"%s\" truncated to \"%s\". This may "
+@@ -670,7 +672,7 @@ static char *automount_path_to_fifo(unsigned logopt, const char *path)
+ * create the fifo name, we will just replace instances of '/' with
+ * '-'.
+ */
+- p = fifo_name + strlen(AUTOFS_LOGPRI_FIFO);
++ p = fifo_name + strlen(fifodir);
+ while (*p != '\0') {
+ if (*p == '/')
+ *p = '-';
+@@ -685,8 +687,9 @@ static char *automount_path_to_fifo(unsigned logopt, const char *path)
+ static int create_logpri_fifo(struct autofs_point *ap)
+ {
+ int ret = -1;
+- int fd;
++ int fd, cl_flags;
+ char *fifo_name;
++ char buf[MAX_ERR_BUF];
+
+ fifo_name = automount_path_to_fifo(ap->logopt, ap->path);
+ if (!fifo_name) {
+@@ -704,18 +707,27 @@ static int create_logpri_fifo(struct autofs_point *ap)
+
+ ret = mkfifo(fifo_name, S_IRUSR|S_IWUSR);
+ if (ret != 0) {
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ crit(ap->logopt,
+- "mkfifo for %s returned %d", fifo_name, errno);
++ "mkfifo for %s failed: %s", fifo_name, estr);
+ goto out_free;
+ }
+
+ fd = open(fifo_name, O_RDWR|O_NONBLOCK);
+ if (fd < 0) {
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ crit(ap->logopt,
+- "Failed to open %s, errno %d", fifo_name, errno);
++ "Failed to open %s: %s", fifo_name, estr);
++ unlink(fifo_name);
++ ret = -1;
+ goto out_free;
+ }
+
++ if ((cl_flags = fcntl(fd, F_GETFD, 0)) != -1) {
++ cl_flags |= FD_CLOEXEC;
++ fcntl(fd, F_SETFD, cl_flags);
++ }
++
+ ap->logpri_fifo = fd;
+
+ out_free:
+@@ -728,6 +740,10 @@ static int destroy_logpri_fifo(struct autofs_point *ap)
+ int ret = -1;
+ int fd = ap->logpri_fifo;
+ char *fifo_name;
++ char buf[MAX_ERR_BUF];
++
++ if (fd == -1)
++ return 0;
+
+ fifo_name = automount_path_to_fifo(ap->logopt, ap->path);
+ if (!fifo_name) {
+@@ -739,8 +755,9 @@ static int destroy_logpri_fifo(struct autofs_point *ap)
+
+ ret = close(fd);
+ if (ret != 0) {
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ warn(ap->logopt,
+- "close for fifo %s returned %d", fifo_name, errno);
++ "close for fifo %s: %s", fifo_name, estr);
+ }
+
+ ret = unlink(fifo_name);
+@@ -760,11 +777,13 @@ static void handle_fifo_message(struct autofs_point *ap, int fd)
+ char buffer[PIPE_BUF];
+ char *end;
+ long pri;
++ char buf[MAX_ERR_BUF];
+
+ memset(buffer, 0, sizeof(buffer));
+ ret = read(fd, &buffer, sizeof(buffer));
+ if (ret < 0) {
+- warn(ap->logopt, "read on fifo returned error %d", errno);
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ warn(ap->logopt, "read on fifo returned error: %s", estr);
+ return;
+ }
+
+@@ -846,16 +865,18 @@ static int set_log_priority(const char *path, int priority)
+ */
+ fd = open(fifo_name, O_WRONLY|O_NONBLOCK);
+ if (fd < 0) {
+- fprintf(stderr, "%s: open of %s failed with %d\n",
+- __FUNCTION__, fifo_name, errno);
++ fprintf(stderr, "%s: open of %s failed with %s\n",
++ __FUNCTION__, fifo_name, strerror(errno));
++ fprintf(stderr, "%s: perhaps the fifo wasn't setup,"
++ " please check your log for more information\n", __FUNCTION__);
+ free(fifo_name);
+ return -1;
+ }
+
+ if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "Failed to change logging priority. ");
+- fprintf(stderr, "write to fifo failed with errno %d.\n",
+- errno);
++ fprintf(stderr, "write to fifo failed: %s.\n",
++ strerror(errno));
+ close(fd);
+ free(fifo_name);
+ return -1;
+@@ -870,6 +891,7 @@ static int set_log_priority(const char *path, int priority)
+ static int get_pkt(struct autofs_point *ap, union autofs_packet_union *pkt)
+ {
+ struct pollfd fds[3];
++ int pollfds = 3;
+ char buf[MAX_ERR_BUF];
+
+ fds[0].fd = ap->pipefd;
+@@ -878,9 +900,11 @@ static int get_pkt(struct autofs_point *ap, union autofs_packet_union *pkt)
+ fds[1].events = POLLIN;
+ fds[2].fd = ap->logpri_fifo;
+ fds[2].events = POLLIN;
++ if (fds[2].fd == -1)
++ pollfds--;
+
+ for (;;) {
+- if (poll(fds, 3, -1) == -1) {
++ if (poll(fds, pollfds, -1) == -1) {
+ char *estr;
+ if (errno == EINTR)
+ continue;
+@@ -930,7 +954,7 @@ static int get_pkt(struct autofs_point *ap, union autofs_packet_union *pkt)
+ if (fds[0].revents & POLLIN)
+ return fullread(ap->pipefd, pkt, kpkt_len);
+
+- if (fds[2].revents & POLLIN) {
++ if (fds[2].fd != -1 && fds[2].revents & POLLIN) {
+ debug(ap->logopt, "message pending on control fifo.");
+ handle_fifo_message(ap, fds[2].fd);
+ }
+@@ -983,7 +1007,6 @@ static int autofs_init_ap(struct autofs_point *ap)
+ crit(ap->logopt,
+ "failed to create commumication pipe for autofs path %s",
+ ap->path);
+- free(ap->path);
+ return -1;
+ }
+
+@@ -1006,7 +1029,6 @@ static int autofs_init_ap(struct autofs_point *ap)
+ "failed create state pipe for autofs path %s", ap->path);
+ close(ap->pipefd);
+ close(ap->kpipefd); /* Close kernel pipe end */
+- free(ap->path);
+ return -1;
+ }
+
+@@ -1021,15 +1043,8 @@ static int autofs_init_ap(struct autofs_point *ap)
+ }
+
+ if (create_logpri_fifo(ap) < 0) {
+- crit(ap->logopt,
+- "failed to create FIFO for path %s\n", ap->path);
+- destroy_logpri_fifo(ap);
+- close(ap->pipefd);
+- close(ap->kpipefd);
+- free(ap->path);
+- close(ap->state_pipe[0]);
+- close(ap->state_pipe[1]);
+- return -1;
++ logmsg("could not create FIFO for path %s\n", ap->path);
++ logmsg("dynamic log level changes not available for %s", ap->path);
+ }
+
+ return 0;
+diff --git a/include/automount.h b/include/automount.h
+index 37a3c0a..b0d1a9c 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -223,8 +223,6 @@ int rmdir_path(struct autofs_point *ap, const char *path, dev_t dev);
+ #define MAPENT_MAX_LEN 4095
+ #define PARSE_MAX_BUF KEY_MAX_LEN + MAPENT_MAX_LEN + 2
+
+-#define AUTOFS_LOGPRI_FIFO "/tmp/autofs.fifo"
+-
+ int lookup_nss_read_master(struct master *master, time_t age);
+ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age);
+ int lookup_enumerate(struct autofs_point *ap,
+diff --git a/lib/master.c b/lib/master.c
+index 2e24ad0..2188bca 100644
+--- a/lib/master.c
++++ b/lib/master.c
+@@ -56,6 +56,7 @@ int master_add_autofs_point(struct master_mapent *entry,
+
+ ap->state_pipe[0] = -1;
+ ap->state_pipe[1] = -1;
++ ap->logpri_fifo = -1;
+
+ ap->path = strdup(entry->path);
+ if (!ap->path) {
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index f8260b1..be50aad 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -44,6 +44,7 @@
+ - fix schema selection in LDAP schema discovery.
+ - update negative mount timeout handling.
+ - fix large group handling (Ryan Thomas).
++- fix for dynamic logging breaking non-sasl build (Guillaume Rousse)
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index bad48bb..93a1b40 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -579,7 +579,9 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
+ list_add_tail(&this->list, ctxt->uri);
+ }
+
++#ifdef WITH_SASL
+ autofs_sasl_done(ctxt);
++#endif
+
+ /* Current server failed connect, try the rest */
+ ldap = find_server(logopt, ctxt);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index ca171a4..a7ac9fb 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -35,6 +35,7 @@
+ - fix typo in autofs(5) man page.
+ - fix map entry expansion when undefined macro is present.
+ - remove unused export validation code.
++- add dynamic logging (adapted from v4 patch from Jeff Moyer).
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 70a3b9d..9ec6923 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -173,7 +173,7 @@ int rmdir_path(struct autofs_point *ap, const char *path, dev_t dev)
+ */
+ memset(&st, 0, sizeof(st));
+ if (lstat(buf, &st) != 0) {
+- crit(ap->logopt, "lstat of %s failed.", buf);
++ crit(ap->logopt, "lstat of %s failed", buf);
+ return -1;
+ }
+
+@@ -234,14 +234,15 @@ int rmdir_path(struct autofs_point *ap, const char *path, dev_t dev)
+ /* Like ftw, except fn gets called twice: before a directory is
+ entered, and after. If the before call returns 0, the directory
+ isn't entered. */
+-static int walk_tree(const char *base, int (*fn) (const char *file,
++static int walk_tree(const char *base, int (*fn) (unsigned logopt,
++ const char *file,
+ const struct stat * st,
+- int, void *), int incl, void *arg)
++ int, void *), int incl, unsigned logopt, void *arg)
+ {
+ char buf[PATH_MAX + 1];
+ struct stat st;
+
+- if (lstat(base, &st) != -1 && (fn) (base, &st, 0, arg)) {
++ if (lstat(base, &st) != -1 && (fn) (logopt, base, &st, 0, arg)) {
+ if (S_ISDIR(st.st_mode)) {
+ struct dirent **de;
+ int n;
+@@ -269,18 +270,18 @@ static int walk_tree(const char *base, int (*fn) (const char *file,
+ return -1;
+ }
+
+- walk_tree(buf, fn, 1, arg);
++ walk_tree(buf, fn, 1, logopt, arg);
+ free(de[n]);
+ }
+ free(de);
+ }
+ if (incl)
+- (fn) (base, &st, 1, arg);
++ (fn) (logopt, base, &st, 1, arg);
+ }
+ return 0;
+ }
+
+-static int rm_unwanted_fn(const char *file, const struct stat *st, int when, void *arg)
++static int rm_unwanted_fn(unsigned logopt, const char *file, const struct stat *st, int when, void *arg)
+ {
+ dev_t dev = *(dev_t *) arg;
+ char buf[MAX_ERR_BUF];
+@@ -293,41 +294,38 @@ static int rm_unwanted_fn(const char *file, const struct stat *st, int when, voi
+ }
+
+ if (lstat(file, &newst)) {
+- crit(LOGOPT_ANY,
+- "unable to stat file, possible race condition");
++ crit(logopt, "unable to stat file, possible race condition");
+ return 0;
+ }
+
+ if (newst.st_dev != dev) {
+- crit(LOGOPT_ANY,
+- "file %s has the wrong device, possible race condition",
++ crit(logopt, "file %s has the wrong device, possible race condition",
+ file);
+ return 0;
+ }
+
+ if (S_ISDIR(newst.st_mode)) {
+- debug(LOGOPT_ANY, "removing directory %s", file);
++ debug(logopt, "removing directory %s", file);
+ if (rmdir(file)) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ "unable to remove directory %s: %s", file, estr);
+ return 0;
+ }
+ } else if (S_ISREG(newst.st_mode)) {
+- crit(LOGOPT_ANY,
+- "attempting to remove files from a mounted "
++ crit(logopt, "attempting to remove files from a mounted "
+ "directory. file %s", file);
+ return 0;
+ } else if (S_ISLNK(newst.st_mode)) {
+- debug(LOGOPT_ANY, "removing symlink %s", file);
++ debug(logopt, "removing symlink %s", file);
+ unlink(file);
+ }
+ return 1;
+ }
+
+-void rm_unwanted(const char *path, int incl, dev_t dev)
++void rm_unwanted(unsigned logopt, const char *path, int incl, dev_t dev)
+ {
+- walk_tree(path, rm_unwanted_fn, incl, &dev);
++ walk_tree(path, rm_unwanted_fn, incl, logopt, &dev);
+ }
+
+ struct counter_args {
+@@ -335,7 +333,7 @@ struct counter_args {
+ dev_t dev;
+ };
+
+-static int counter_fn(const char *file, const struct stat *st, int when, void *arg)
++static int counter_fn(unsigned logopt, const char *file, const struct stat *st, int when, void *arg)
+ {
+ struct counter_args *counter = (struct counter_args *) arg;
+
+@@ -349,14 +347,14 @@ static int counter_fn(const char *file, const struct stat *st, int when, void *a
+ }
+
+ /* Count mounted filesystems and symlinks */
+-int count_mounts(const char *path, dev_t dev)
++int count_mounts(unsigned logopt, const char *path, dev_t dev)
+ {
+ struct counter_args counter;
+
+ counter.count = 0;
+ counter.dev = dev;
+
+- if (walk_tree(path, counter_fn, 0, &counter) == -1)
++ if (walk_tree(path, counter_fn, 0, logopt, &counter) == -1)
+ return -1;
+
+ return counter.count;
+@@ -368,9 +366,9 @@ static void check_rm_dirs(struct autofs_point *ap, const char *path, int incl)
+ (ap->state == ST_SHUTDOWN_PENDING ||
+ ap->state == ST_SHUTDOWN_FORCE ||
+ ap->state == ST_SHUTDOWN))
+- rm_unwanted(path, incl, ap->dev);
++ rm_unwanted(ap->logopt, path, incl, ap->dev);
+ else if (ap->ghost && (ap->type == LKP_INDIRECT))
+- rm_unwanted(path, 0, ap->dev);
++ rm_unwanted(ap->logopt, path, 0, ap->dev);
+ }
+
+ /* Try to purge cache entries kept around due to existing mounts */
+@@ -466,7 +464,7 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ cache_multi_lock(me->parent);
+ if (umount_multi_triggers(ap, root, me, base)) {
+ warn(ap->logopt,
+- "could not umount some offsets under %s", path);
++ "some offset mounts still present under %s", path);
+ left++;
+ }
+ cache_multi_unlock(me->parent);
+@@ -483,7 +481,7 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ * it already to ensure it's ok to remove any offset triggers.
+ */
+ if (!is_mm_root && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
+- msg("unmounting dir = %s", path);
++ info(ap->logopt, "unmounting dir = %s", path);
+ if (umount_ent(ap, path)) {
+ warn(ap->logopt, "could not umount dir %s", path);
+ left++;
+@@ -576,35 +574,35 @@ int umount_autofs(struct autofs_point *ap, int force)
+ return ret;
+ }
+
+-int send_ready(int ioctlfd, unsigned int wait_queue_token)
++int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token)
+ {
+ char buf[MAX_ERR_BUF];
+
+ if (wait_queue_token == 0)
+ return 0;
+
+- debug(LOGOPT_NONE, "token = %d", wait_queue_token);
++ debug(logopt, "token = %d", wait_queue_token);
+
+ if (ioctl(ioctlfd, AUTOFS_IOC_READY, wait_queue_token) < 0) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "AUTOFS_IOC_READY: error %s", estr);
++ logerr("AUTOFS_IOC_READY: error %s", estr);
+ return 1;
+ }
+ return 0;
+ }
+
+-int send_fail(int ioctlfd, unsigned int wait_queue_token)
++int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token)
+ {
+ char buf[MAX_ERR_BUF];
+
+ if (wait_queue_token == 0)
+ return 0;
+
+- debug(LOGOPT_NONE, "token = %d", wait_queue_token);
++ debug(logopt, "token = %d", wait_queue_token);
+
+ if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, wait_queue_token) < 0) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "AUTOFS_IOC_FAIL: error %s", estr);
++ logerr("AUTOFS_IOC_FAIL: error %s", estr);
+ return 1;
+ }
+ return 0;
+@@ -649,23 +647,245 @@ static int fullread(int fd, void *ptr, size_t len)
+ return len;
+ }
+
++static char *automount_path_to_fifo(unsigned logopt, const char *path)
++{
++ char *fifo_name, *p;
++ int name_len = strlen(path) + strlen(AUTOFS_LOGPRI_FIFO) + 1;
++ int ret;
++
++ fifo_name = malloc(name_len);
++ if (!fifo_name)
++ return NULL;
++ ret = snprintf(fifo_name, name_len, "%s%s",
++ AUTOFS_LOGPRI_FIFO, path);
++ if (ret >= name_len) {
++ info(logopt,
++ "fifo path for \"%s\" truncated to \"%s\". This may "
++ "lead to --set-log-priority commands being sent to the "
++ "wrong automount daemon.", path, fifo_name);
++ }
++
++ /*
++ * An automount path can be made up of subdirectories. So, to
++ * create the fifo name, we will just replace instances of '/' with
++ * '-'.
++ */
++ p = fifo_name + strlen(AUTOFS_LOGPRI_FIFO);
++ while (*p != '\0') {
++ if (*p == '/')
++ *p = '-';
++ p++;
++ }
++
++ debug(logopt, "fifo name %s",fifo_name);
++
++ return fifo_name;
++}
++
++static int create_logpri_fifo(struct autofs_point *ap)
++{
++ int ret = -1;
++ int fd;
++ char *fifo_name;
++
++ fifo_name = automount_path_to_fifo(ap->logopt, ap->path);
++ if (!fifo_name) {
++ crit(ap->logopt, "Failed to allocate memory!");
++ goto out_free; /* free(NULL) is okay */
++ }
++
++ ret = unlink(fifo_name);
++ if (ret != 0 && errno != ENOENT) {
++ crit(ap->logopt,
++ "Failed to unlink FIFO. Is the automount daemon "
++ "already running?");
++ goto out_free;
++ }
++
++ ret = mkfifo(fifo_name, S_IRUSR|S_IWUSR);
++ if (ret != 0) {
++ crit(ap->logopt,
++ "mkfifo for %s returned %d", fifo_name, errno);
++ goto out_free;
++ }
++
++ fd = open(fifo_name, O_RDWR|O_NONBLOCK);
++ if (fd < 0) {
++ crit(ap->logopt,
++ "Failed to open %s, errno %d", fifo_name, errno);
++ goto out_free;
++ }
++
++ ap->logpri_fifo = fd;
++
++out_free:
++ free(fifo_name);
++ return ret;
++}
++
++static int destroy_logpri_fifo(struct autofs_point *ap)
++{
++ int ret = -1;
++ int fd = ap->logpri_fifo;
++ char *fifo_name;
++
++ fifo_name = automount_path_to_fifo(ap->logopt, ap->path);
++ if (!fifo_name) {
++ crit(ap->logopt, "Failed to allocate memory!");
++ goto out_free; /* free(NULL) is okay */
++ }
++
++ ap->logpri_fifo = -1;
++
++ ret = close(fd);
++ if (ret != 0) {
++ warn(ap->logopt,
++ "close for fifo %s returned %d", fifo_name, errno);
++ }
++
++ ret = unlink(fifo_name);
++ if (ret != 0) {
++ warn(ap->logopt,
++ "Failed to unlink FIFO. Was the fifo created OK?");
++ }
++
++out_free:
++ free(fifo_name);
++ return ret;
++}
++
++static void handle_fifo_message(struct autofs_point *ap, int fd)
++{
++ int ret;
++ char buffer[PIPE_BUF];
++ char *end;
++ long pri;
++
++ memset(buffer, 0, sizeof(buffer));
++ ret = read(fd, &buffer, sizeof(buffer));
++ if (ret < 0) {
++ warn(ap->logopt, "read on fifo returned error %d", errno);
++ return;
++ }
++
++ if (ret != 2) {
++ debug(ap->logopt, "expected 2 bytes, received %d.", ret);
++ return;
++ }
++
++ errno = 0;
++ pri = strtol(buffer, &end, 10);
++ if ((pri == LONG_MIN || pri == LONG_MAX) && errno == ERANGE) {
++ debug(ap->logopt, "strtol reported an %s. Failed to set "
++ "log priority.", pri == LONG_MIN ? "underflow" : "overflow");
++ return;
++ }
++ if ((pri == 0 && errno == EINVAL) || end == buffer) {
++ debug(ap->logopt, "priority is expected to be an integer "
++ "in the range 0-7 inclusive.");
++ return;
++ }
++
++ if (pri > LOG_DEBUG || pri < LOG_EMERG) {
++ debug(ap->logopt, "invalid log priority (%ld) received "
++ "on fifo", pri);
++ return;
++ }
++
++ /*
++ * OK, the message passed all of the sanity checks. The
++ * automounter actually only supports three log priorities.
++ * Everything is logged at log level debug, deamon messages
++ * and everything except debug messages are logged with the
++ * verbose setting and only error and critical messages are
++ * logged when debugging isn't enabled.
++ */
++ if (pri >= LOG_WARNING) {
++ if (pri == LOG_DEBUG) {
++ set_log_debug_ap(ap);
++ info(ap->logopt, "Debug logging set for %s", ap->path);
++ } else {
++ set_log_verbose_ap(ap);
++ info(ap->logopt, "Verbose logging set for %s", ap->path);
++ }
++ } else {
++ if (ap->logopt & LOGOPT_ANY)
++ info(ap->logopt, "Basic logging set for %s", ap->path);
++ set_log_norm_ap(ap);
++ }
++}
++
++static int set_log_priority(const char *path, int priority)
++{
++ int fd;
++ char *fifo_name;
++ char buf[2];
++
++ if (priority > LOG_DEBUG || priority < LOG_EMERG) {
++ fprintf(stderr, "Log priority %d is invalid.\n", priority);
++ fprintf(stderr, "Please spcify a number in the range 0-7.\n");
++ return -1;
++ }
++
++ /*
++ * This is an ascii based protocol, so we want the string
++ * representation of the integer log priority.
++ */
++ snprintf(buf, sizeof(buf), "%d", priority);
++
++ fifo_name = automount_path_to_fifo(LOGOPT_NONE, path);
++ if (!fifo_name) {
++ fprintf(stderr, "%s: Failed to allocate memory!\n",
++ __FUNCTION__);
++ return -1;
++ }
++
++ /*
++ * Specify O_NONBLOCK so that the open will fail if there is no
++ * daemon reading from the other side of the FIFO.
++ */
++ fd = open(fifo_name, O_WRONLY|O_NONBLOCK);
++ if (fd < 0) {
++ fprintf(stderr, "%s: open of %s failed with %d\n",
++ __FUNCTION__, fifo_name, errno);
++ free(fifo_name);
++ return -1;
++ }
++
++ if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
++ fprintf(stderr, "Failed to change logging priority. ");
++ fprintf(stderr, "write to fifo failed with errno %d.\n",
++ errno);
++ close(fd);
++ free(fifo_name);
++ return -1;
++ }
++ close(fd);
++ free(fifo_name);
++ fprintf(stdout, "Successfully set log priority for %s.\n", path);
++
++ return 0;
++}
++
+ static int get_pkt(struct autofs_point *ap, union autofs_packet_union *pkt)
+ {
+- struct pollfd fds[2];
++ struct pollfd fds[3];
+ char buf[MAX_ERR_BUF];
+
+ fds[0].fd = ap->pipefd;
+ fds[0].events = POLLIN;
+ fds[1].fd = ap->state_pipe[0];
+ fds[1].events = POLLIN;
++ fds[2].fd = ap->logpri_fifo;
++ fds[2].events = POLLIN;
+
+ for (;;) {
+- if (poll(fds, 2, -1) == -1) {
++ if (poll(fds, 3, -1) == -1) {
+ char *estr;
+ if (errno == EINTR)
+ continue;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, "poll failed: %s", estr);
++ logerr("poll failed: %s", estr);
+ return -1;
+ }
+
+@@ -709,6 +929,11 @@ static int get_pkt(struct autofs_point *ap, union autofs_packet_union *pkt)
+
+ if (fds[0].revents & POLLIN)
+ return fullread(ap->pipefd, pkt, kpkt_len);
++
++ if (fds[2].revents & POLLIN) {
++ debug(ap->logopt, "message pending on control fifo.");
++ handle_fifo_message(ap, fds[2].fd);
++ }
+ }
+ }
+
+@@ -730,21 +955,93 @@ int do_expire(struct autofs_point *ap, const char *name, int namelen)
+ return 1;
+ }
+
+- msg("expiring path %s", buf);
++ info(ap->logopt, "expiring path %s", buf);
+
+ ret = umount_multi(ap, buf, 1);
+ if (ret == 0)
+- msg("expired %s", buf);
++ info(ap->logopt, "expired %s", buf);
+ else
+ warn(ap->logopt, "couldn't complete expire of %s", buf);
+
+ return ret;
+ }
+
++static int autofs_init_ap(struct autofs_point *ap)
++{
++ int pipefd[2], cl_flags;
++
++ if ((ap->state != ST_INIT)) {
++ /* This can happen if an autofs process is already running*/
++ error(ap->logopt, "bad state %d", ap->state);
++ return -1;
++ }
++
++ ap->pipefd = ap->kpipefd = ap->ioctlfd = -1;
++
++ /* Pipe for kernel communications */
++ if (pipe(pipefd) < 0) {
++ crit(ap->logopt,
++ "failed to create commumication pipe for autofs path %s",
++ ap->path);
++ free(ap->path);
++ return -1;
++ }
++
++ ap->pipefd = pipefd[0];
++ ap->kpipefd = pipefd[1];
++
++ if ((cl_flags = fcntl(ap->pipefd, F_GETFD, 0)) != -1) {
++ cl_flags |= FD_CLOEXEC;
++ fcntl(ap->pipefd, F_SETFD, cl_flags);
++ }
++
++ if ((cl_flags = fcntl(ap->kpipefd, F_GETFD, 0)) != -1) {
++ cl_flags |= FD_CLOEXEC;
++ fcntl(ap->kpipefd, F_SETFD, cl_flags);
++ }
++
++ /* Pipe state changes from signal handler to main loop */
++ if (pipe(ap->state_pipe) < 0) {
++ crit(ap->logopt,
++ "failed create state pipe for autofs path %s", ap->path);
++ close(ap->pipefd);
++ close(ap->kpipefd); /* Close kernel pipe end */
++ free(ap->path);
++ return -1;
++ }
++
++ if ((cl_flags = fcntl(ap->state_pipe[0], F_GETFD, 0)) != -1) {
++ cl_flags |= FD_CLOEXEC;
++ fcntl(ap->state_pipe[0], F_SETFD, cl_flags);
++ }
++
++ if ((cl_flags = fcntl(ap->state_pipe[1], F_GETFD, 0)) != -1) {
++ cl_flags |= FD_CLOEXEC;
++ fcntl(ap->state_pipe[1], F_SETFD, cl_flags);
++ }
++
++ if (create_logpri_fifo(ap) < 0) {
++ crit(ap->logopt,
++ "failed to create FIFO for path %s\n", ap->path);
++ destroy_logpri_fifo(ap);
++ close(ap->pipefd);
++ close(ap->kpipefd);
++ free(ap->path);
++ close(ap->state_pipe[0]);
++ close(ap->state_pipe[1]);
++ return -1;
++ }
++
++ return 0;
++}
++
+ static int mount_autofs(struct autofs_point *ap)
+ {
+ int status = 0;
+
++ if (autofs_init_ap(ap) != 0)
++ return -1;
++
+ if (ap->type == LKP_DIRECT)
+ status = mount_autofs_direct(ap);
+ else
+@@ -841,9 +1138,8 @@ static void become_daemon(unsigned foreground)
+ fclose(pidfp);
+ } else {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- warn(LOGOPT_ANY,
+- "failed to write pid file %s: %s",
+- pid_file, estr);
++ logerr("failed to write pid file %s: %s",
++ pid_file, estr);
+ pid_file = NULL;
+ }
+ }
+@@ -889,12 +1185,12 @@ static void *do_notify_state(void *arg)
+
+ master = mrc.master;
+
+- debug(master->default_logging, "signal %d", sig);
++ debug(master->logopt, "signal %d", sig);
+
+ mrc.signaled = 1;
+ status = pthread_cond_signal(&mrc.cond);
+ if (status) {
+- error(master->default_logging,
++ error(master->logopt,
+ "failed to signal state notify condition");
+ status = pthread_mutex_unlock(&mrc.mutex);
+ if (status)
+@@ -923,7 +1219,7 @@ static pthread_t do_signals(struct master *master, int sig)
+
+ status = pthread_create(&thid, &thread_attr, do_notify_state, &r_sig);
+ if (status) {
+- error(master->default_logging,
++ error(master->logopt,
+ "mount state notify thread create failed");
+ status = pthread_mutex_unlock(&mrc.mutex);
+ if (status)
+@@ -951,6 +1247,7 @@ static pthread_t do_signals(struct master *master, int sig)
+ static void *do_read_master(void *arg)
+ {
+ struct master *master;
++ unsigned int logopt;
+ time_t age;
+ int readall = 1;
+ int status;
+@@ -961,11 +1258,12 @@ static void *do_read_master(void *arg)
+
+ master = mrc.master;
+ age = mrc.age;
++ logopt = master->logopt;
+
+ mrc.signaled = 1;
+ status = pthread_cond_signal(&mrc.cond);
+ if (status) {
+- error(master->default_logging,
++ error(logopt,
+ "failed to signal master read map condition");
+ master->reading = 0;
+ status = pthread_mutex_unlock(&mrc.mutex);
+@@ -989,6 +1287,7 @@ static void *do_read_master(void *arg)
+
+ static int do_hup_signal(struct master *master, time_t age)
+ {
++ unsigned int logopt = master->logopt;
+ pthread_t thid;
+ int status;
+
+@@ -1007,7 +1306,7 @@ static int do_hup_signal(struct master *master, time_t age)
+
+ status = pthread_create(&thid, &thread_attr, do_read_master, NULL);
+ if (status) {
+- error(master->default_logging,
++ error(logopt,
+ "master read map thread create failed");
+ master->reading = 0;
+ status = pthread_mutex_unlock(&mrc.mutex);
+@@ -1062,8 +1361,7 @@ static void *statemachine(void *arg)
+ break;
+
+ default:
+- error(master_list->default_logging,
+- "got unexpected signal %d!", sig);
++ logerr("got unexpected signal %d!", sig);
+ continue;
+ }
+ }
+@@ -1134,10 +1432,11 @@ static void handle_mounts_cleanup(void *arg)
+ struct autofs_point *ap;
+ char path[PATH_MAX + 1];
+ char buf[MAX_ERR_BUF];
+- unsigned int clean = 0, submount;
++ unsigned int clean = 0, submount, logopt;
+
+ ap = (struct autofs_point *) arg;
+
++ logopt = ap->logopt;
+ submount = ap->submount;
+
+ strcpy(path, ap->path);
+@@ -1152,6 +1451,7 @@ static void handle_mounts_cleanup(void *arg)
+
+ umount_autofs(ap, 1);
+
++ destroy_logpri_fifo(ap);
+ master_signal_submount(ap, MASTER_SUBMNT_JOIN);
+ master_remove_mapent(ap->entry);
+ master_free_mapent_sources(ap->entry, 1);
+@@ -1162,12 +1462,12 @@ static void handle_mounts_cleanup(void *arg)
+ if (clean) {
+ if (rmdir(path) == -1) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- warn(LOGOPT_NONE, "failed to remove dir %s: %s",
++ warn(logopt, "failed to remove dir %s: %s",
+ path, estr);
+ }
+ }
+
+- msg("shut down path %s", path);
++ info(logopt, "shut down path %s", path);
+
+ /* If we are the last tell the state machine to shutdown */
+ if (!submount && master_list_empty(master_list))
+@@ -1190,7 +1490,7 @@ void *handle_mounts(void *arg)
+
+ status = pthread_mutex_lock(&suc.mutex);
+ if (status) {
+- crit(ap->logopt, "failed to lock startup condition mutex!");
++ logerr("failed to lock startup condition mutex!");
+ fatal(status);
+ }
+
+@@ -1204,7 +1504,7 @@ void *handle_mounts(void *arg)
+ }
+
+ if (ap->ghost && ap->type != LKP_DIRECT)
+- msg("ghosting enabled");
++ info(ap->logopt, "ghosting enabled");
+
+ suc.status = 0;
+ pthread_cleanup_pop(1);
+@@ -1356,6 +1656,8 @@ static void usage(void)
+ " use ramdom replicated server selection\n"
+ " -O --global-options\n"
+ " specify global mount options\n"
++ " -l --set-log-priority priority path [path,...]\n"
++ " set daemon log verbosity\n"
+ " -V --version print version, build config and exit\n"
+ , program);
+ }
+@@ -1437,9 +1739,45 @@ static void show_build_info(void)
+ return;
+ }
+
++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 },
++ { "notice", LOG_NOTICE },
++ { "panic", LOG_EMERG }, /* DEPRECATED */
++ { "warn", LOG_WARNING }, /* DEPRECATED */
++ { "warning", LOG_WARNING },
++ { NULL, -1 },
++};
++
++static int convert_log_priority(char *priority_name)
++{
++ CODE *priority_mapping;
++
++ for (priority_mapping = prioritynames;
++ priority_mapping->c_name != NULL;
++ priority_mapping++) {
++
++ if (!strcasecmp(priority_name, priority_mapping->c_name))
++ return priority_mapping->c_val;
++ }
++
++ return -1;
++}
++
+ int main(int argc, char *argv[])
+ {
+ int res, opt, status;
++ int logpri = -1;
+ unsigned ghost, logging;
+ unsigned foreground, have_global_options;
+ time_t timeout;
+@@ -1457,6 +1795,7 @@ int main(int argc, char *argv[])
+ {"random-multimount-selection", 0, 0, 'r'},
+ {"global-options", 1, 0, 'O'},
+ {"version", 0, 0, 'V'},
++ {"set-log-priority", 1, 0, 'l'},
+ {0, 0, 0, 0}
+ };
+
+@@ -1477,7 +1816,7 @@ int main(int argc, char *argv[])
+ foreground = 0;
+
+ opterr = 0;
+- while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:", long_options, NULL)) != EOF) {
++ while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:", long_options, NULL)) != EOF) {
+ switch (opt) {
+ case 'h':
+ usage();
+@@ -1525,6 +1864,23 @@ int main(int argc, char *argv[])
+ program);
+ break;
+
++ case 'l':
++ if (isalpha(*optarg)) {
++ logpri = convert_log_priority(optarg);
++ if (logpri < 0) {
++ fprintf(stderr, "Invalid log priority:"
++ " %s\n", optarg);
++ exit(1);
++ }
++ } else if (isdigit(*optarg)) {
++ logpri = getnumopt(optarg, opt);
++ } else {
++ fprintf(stderr, "non-alphanumeric character "
++ "found in log priority. Aborting.\n");
++ exit(1);
++ }
++ break;
++
+ case '?':
+ case ':':
+ printf("%s: Ambiguous or unknown options\n", program);
+@@ -1548,6 +1904,26 @@ int main(int argc, char *argv[])
+ argv += optind;
+ argc -= optind;
+
++ if (logpri >= 0) {
++ int exit_code = 0;
++ int i;
++
++ /*
++ * The remaining argv elements are the paths for which
++ * log priorities must be changed.
++ */
++ for (i = 0; i < argc; i++) {
++ if (set_log_priority(argv[i], logpri) < 0)
++ exit_code = 1;
++ }
++ if (argc < 1) {
++ fprintf(stderr,
++ "--set-log-priority requires a path.\n");
++ exit_code = 1;
++ }
++ exit(exit_code);
++ }
++
+ if (is_automount_running() > 0) {
+ fprintf(stderr, "%s: program is already running.\n",
+ program);
+@@ -1572,7 +1948,7 @@ int main(int argc, char *argv[])
+ rlim.rlim_max = MAX_OPEN_FILES;
+ res = setrlimit(RLIMIT_NOFILE, &rlim);
+ if (res)
+- warn(LOGOPT_NONE,
++ warn(logging,
+ "can't increase open file limit - continuing");
+
+ #if ENABLE_CORES
+@@ -1580,7 +1956,7 @@ int main(int argc, char *argv[])
+ rlim.rlim_max = RLIM_INFINITY;
+ res = setrlimit(RLIMIT_CORE, &rlim);
+ if (res)
+- warn(LOGOPT_NONE,
++ warn(logging,
+ "can't increase core file limit - continuing");
+ #endif
+
+@@ -1592,15 +1968,14 @@ int main(int argc, char *argv[])
+ master_list = master_new(argv[0], timeout, ghost);
+
+ if (!master_list) {
+- crit(LOGOPT_ANY, "%s: can't create master map %s",
++ logerr("%s: can't create master map %s",
+ program, argv[0]);
+ close(start_pipefd[1]);
+ exit(1);
+ }
+
+ if (pthread_attr_init(&thread_attr)) {
+- crit(LOGOPT_ANY,
+- "%s: failed to init thread attribute struct!",
++ logerr("%s: failed to init thread attribute struct!",
+ program);
+ close(start_pipefd[1]);
+ exit(1);
+@@ -1608,8 +1983,7 @@ int main(int argc, char *argv[])
+
+ if (pthread_attr_setdetachstate(
+ &thread_attr, PTHREAD_CREATE_DETACHED)) {
+- crit(LOGOPT_ANY,
+- "%s: failed to set detached thread attribute!",
++ logerr("%s: failed to set detached thread attribute!",
+ program);
+ close(start_pipefd[1]);
+ exit(1);
+@@ -1618,38 +1992,37 @@ int main(int argc, char *argv[])
+ #ifdef _POSIX_THREAD_ATTR_STACKSIZE
+ if (pthread_attr_setstacksize(
+ &thread_attr, PTHREAD_STACK_MIN*64)) {
+- crit(LOGOPT_ANY,
+- "%s: failed to set stack size thread attribute!",
+- program);
++ logerr("%s: failed to set stack size thread attribute!",
++ program);
+ close(start_pipefd[1]);
+ exit(1);
+ }
+ #endif
+
+- msg("Starting automounter version %s, master map %s",
++ info(logging, "Starting automounter version %s, master map %s",
+ version, master_list->name);
+- msg("using kernel protocol version %d.%02d",
++ info(logging, "using kernel protocol version %d.%02d",
+ get_kver_major(), get_kver_minor());
+
+ status = pthread_key_create(&key_thread_stdenv_vars,
+ key_thread_stdenv_vars_destroy);
+ if (status) {
+- crit(LOGOPT_ANY,
+- "failed to create thread data key for std env vars!");
++ logerr("%s: failed to create thread data key for std env vars!",
++ program);
+ master_kill(master_list);
+ close(start_pipefd[1]);
+ exit(1);
+ }
+
+ if (!alarm_start_handler()) {
+- crit(LOGOPT_ANY, "failed to create alarm handler thread!");
++ logerr("%s: failed to create alarm handler thread!", program);
+ master_kill(master_list);
+ close(start_pipefd[1]);
+ exit(1);
+ }
+
+ if (!st_start_handler()) {
+- crit(LOGOPT_ANY, "failed to create FSM handler thread!");
++ logerr("%s: failed to create FSM handler thread!", program);
+ master_kill(master_list);
+ close(start_pipefd[1]);
+ exit(1);
+@@ -1685,5 +2058,7 @@ int main(int argc, char *argv[])
+ if (dh)
+ dlclose(dh);
+ #endif
++ info(logging, "autofs stopped");
++
+ exit(0);
+ }
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 9a39a6f..4ab4204 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -86,61 +86,6 @@ static void mnts_cleanup(void *arg)
+ return;
+ }
+
+-static int autofs_init_direct(struct autofs_point *ap)
+-{
+- int pipefd[2], cl_flags;
+-
+- if ((ap->state != ST_INIT)) {
+- /* This can happen if an autofs process is already running*/
+- error(ap->logopt, "bad state %d", ap->state);
+- return -1;
+- }
+-
+- ap->pipefd = ap->kpipefd = ap->ioctlfd = -1;
+-
+- /* Pipe for kernel communications */
+- if (pipe(pipefd) < 0) {
+- crit(ap->logopt,
+- "failed to create commumication pipe for autofs path %s",
+- ap->path);
+- return -1;
+- }
+-
+- ap->pipefd = pipefd[0];
+- ap->kpipefd = pipefd[1];
+-
+- if ((cl_flags = fcntl(ap->pipefd, F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->pipefd, F_SETFD, cl_flags);
+- }
+-
+- if ((cl_flags = fcntl(ap->kpipefd, F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->kpipefd, F_SETFD, cl_flags);
+- }
+-
+- /* Pipe state changes from signal handler to main loop */
+- if (pipe(ap->state_pipe) < 0) {
+- crit(ap->logopt, "failed create state pipe for autofs path %s",
+- ap->path);
+- close(ap->pipefd);
+- close(ap->kpipefd);
+- return -1;
+- }
+-
+- if ((cl_flags = fcntl(ap->state_pipe[0], F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->state_pipe[0], F_SETFD, cl_flags);
+- }
+-
+- if ((cl_flags = fcntl(ap->state_pipe[1], F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->state_pipe[1], F_SETFD, cl_flags);
+- }
+-
+- return 0;
+-}
+-
+ int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
+ {
+ char buf[MAX_ERR_BUF];
+@@ -241,10 +186,10 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, stru
+
+ force_umount:
+ if (rv != 0) {
+- msg("forcing umount of direct mount %s", me->key);
++ info(ap->logopt, "forcing umount of direct mount %s", me->key);
+ rv = umount2(me->key, MNT_DETACH);
+ } else
+- msg("umounted direct mount %s", me->key);
++ info(ap->logopt, "umounted direct mount %s", me->key);
+
+ if (!rv && me->dir_created) {
+ if (rmdir(me->key) == -1) {
+@@ -326,7 +271,7 @@ static int unlink_mount_tree(struct autofs_point *ap, struct list_head *list)
+ continue;
+
+ if (strcmp(mnt->fs_type, "autofs"))
+- rv = spawn_umount(log_debug, "-l", mnt->path, NULL);
++ rv = spawn_umount(ap->logopt, "-l", mnt->path, NULL);
+ else
+ rv = umount2(mnt->path, MNT_DETACH);
+ if (rv == -1) {
+@@ -475,13 +420,15 @@ int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struc
+ ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
+
+ if (ap->exp_timeout)
+- msg("mounted direct mount on %s "
++ info(ap->logopt,
++ "mounted direct mount on %s "
+ "with timeout %u, freq %u seconds", me->key,
+ (unsigned int) ap->exp_timeout,
+ (unsigned int) ap->exp_runfreq);
+ else
+- msg("mounted direct mount on %s with timeouts disabled",
+- me->key);
++ info(ap->logopt,
++ "mounted direct mount on %s with timeouts disabled",
++ me->key);
+
+ ret = fstat(ioctlfd, &st);
+ if (ret == -1) {
+@@ -522,9 +469,6 @@ int mount_autofs_direct(struct autofs_point *ap)
+ return -1;
+ }
+
+- if (autofs_init_direct(ap))
+- return -1;
+-
+ /* TODO: check map type */
+ if (lookup_nss_read_map(ap, NULL, now))
+ lookup_prune_cache(ap, now);
+@@ -607,7 +551,7 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+ /* offset isn't mounted, return success and try to recover */
+ if (!is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
+ debug(ap->logopt,
+- "offset %s unexpectedly not mounted",
++ "offset %s not mounted",
+ me->key);
+ return 0;
+ }
+@@ -627,7 +571,7 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+ rv = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status);
+ if (rv) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, "ioctl failed: %s", estr);
++ logerr("ioctl failed: %s", estr);
+ return 1;
+ } else if (!status) {
+ if (ap->state != ST_SHUTDOWN_FORCE) {
+@@ -692,10 +636,10 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+
+ force_umount:
+ if (rv != 0) {
+- msg("forcing umount of offset mount %s", me->key);
++ info(ap->logopt, "forcing umount of offset mount %s", me->key);
+ rv = umount2(me->key, MNT_DETACH);
+ } else
+- msg("umounted offset mount %s", me->key);
++ info(ap->logopt, "umounted offset mount %s", me->key);
+
+ if (!rv && me->dir_created) {
+ if (rmdir(me->key) == -1) {
+@@ -868,7 +812,7 @@ static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsig
+ return 0;
+ }
+
+- retries = (count_mounts(path, st.st_dev) + 1) * EXPIRE_RETRIES;
++ retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
+
+ while (retries--) {
+ struct timespec tm = {0, 100000000};
+@@ -1018,7 +962,7 @@ void *expire_proc_direct(void *arg)
+
+ if (me->ioctlfd != -1 &&
+ fstat(ioctlfd, &st) != -1 &&
+- !count_mounts(next->path, st.st_dev)) {
++ !count_mounts(ap->logopt, next->path, st.st_dev)) {
+ close(ioctlfd);
+ me->ioctlfd = -1;
+ }
+@@ -1049,6 +993,9 @@ void *expire_proc_direct(void *arg)
+ }
+ pthread_cleanup_pop(1);
+
++ if (left)
++ info(ap->logopt, "%d remaining in %s", left, ap->path);
++
+ ec.status = left;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+@@ -1072,7 +1019,7 @@ static void pending_cond_destroy(void *arg)
+ static void expire_send_fail(void *arg)
+ {
+ struct pending_args *mt = arg;
+- send_fail(mt->ioctlfd, mt->wait_queue_token);
++ send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ }
+
+ static void free_pending_args(void *arg)
+@@ -1124,14 +1071,14 @@ static void *do_expire_direct(void *arg)
+ status = do_expire(ap, mt->name, len);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
+ if (status)
+- send_fail(mt->ioctlfd, mt->wait_queue_token);
++ send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ else {
+ struct mapent *me;
+ cache_readlock(mt->mc);
+ me = cache_lookup_distinct(mt->mc, mt->name);
+ me->ioctlfd = -1;
+ cache_unlock(mt->mc);
+- send_ready(mt->ioctlfd, mt->wait_queue_token);
++ send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ close(mt->ioctlfd);
+ }
+ pthread_setcancelstate(state, NULL);
+@@ -1194,7 +1141,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
+ if (!mt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(ap->logopt, "malloc: %s", estr);
+- send_fail(me->ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token);
+ cache_unlock(mc);
+ pthread_setcancelstate(state, NULL);
+ return 1;
+@@ -1223,7 +1170,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
+ status = pthread_create(&thid, &thread_attr, do_expire_direct, mt);
+ if (status) {
+ error(ap->logopt, "expire thread create failed");
+- send_fail(mt->ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token);
+ cache_unlock(mc);
+ expire_mutex_unlock(NULL);
+ pending_cond_destroy(mt);
+@@ -1252,7 +1199,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
+ static void mount_send_fail(void *arg)
+ {
+ struct pending_args *mt = arg;
+- send_fail(mt->ioctlfd, mt->wait_queue_token);
++ send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ close(mt->ioctlfd);
+ }
+
+@@ -1319,7 +1266,7 @@ static void *do_mount_direct(void *arg)
+
+ pthread_setcancelstate(state, NULL);
+
+- msg("attempting to mount entry %s", mt->name);
++ info(ap->logopt, "attempting to mount entry %s", mt->name);
+
+ /*
+ * Setup thread specific data values for macro
+@@ -1445,16 +1392,16 @@ cont:
+ cache_unlock(mt->mc);
+ if (set_fd) {
+ me->ioctlfd = mt->ioctlfd;
+- send_ready(mt->ioctlfd, mt->wait_queue_token);
++ send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ } else {
+- send_ready(mt->ioctlfd, mt->wait_queue_token);
++ send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ close(mt->ioctlfd);
+ }
+- msg("mounted %s", mt->name);
++ info(ap->logopt, "mounted %s", mt->name);
+ } else {
+- send_fail(mt->ioctlfd, mt->wait_queue_token);
++ send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ close(mt->ioctlfd);
+- msg("failed to mount %s", mt->name);
++ info(ap->logopt, "failed to mount %s", mt->name);
+ }
+ pthread_setcancelstate(state, NULL);
+
+@@ -1505,7 +1452,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
+ * Shouldn't happen as the kernel is telling us
+ * someone has walked on our mount point.
+ */
+- crit(ap->logopt, "can't find map entry for (%lu,%lu)",
++ logerr("can't find map entry for (%lu,%lu)",
+ (unsigned long) pkt->dev, (unsigned long) pkt->ino);
+ pthread_setcancelstate(state, NULL);
+ return 1;
+@@ -1538,7 +1485,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
+ if (ap->state == ST_SHUTDOWN_PENDING ||
+ ap->state == ST_SHUTDOWN_FORCE ||
+ ap->state == ST_SHUTDOWN) {
+- send_fail(ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
+ close(ioctlfd);
+ cache_unlock(mc);
+ pthread_setcancelstate(state, NULL);
+@@ -1549,7 +1496,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
+ if (!mt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(ap->logopt, "malloc: %s", estr);
+- send_fail(ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
+ close(ioctlfd);
+ cache_unlock(mc);
+ pthread_setcancelstate(state, NULL);
+@@ -1578,7 +1525,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
+ status = pthread_create(&thid, &thread_attr, do_mount_direct, mt);
+ if (status) {
+ error(ap->logopt, "missing mount thread create failed");
+- send_fail(ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
+ close(ioctlfd);
+ cache_unlock(mc);
+ mount_mutex_unlock(NULL);
+diff --git a/daemon/indirect.c b/daemon/indirect.c
+index 02e7045..5c422c8 100644
+--- a/daemon/indirect.c
++++ b/daemon/indirect.c
+@@ -43,63 +43,6 @@ extern pthread_attr_t thread_attr;
+ static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+-static int autofs_init_indirect(struct autofs_point *ap)
+-{
+- int pipefd[2], cl_flags;
+-
+- if ((ap->state != ST_INIT)) {
+- /* This can happen if an autofs process is already running*/
+- error(ap->logopt, "bad state %d", ap->state);
+- return -1;
+- }
+-
+- ap->pipefd = ap->kpipefd = ap->ioctlfd = -1;
+-
+- /* Pipe for kernel communications */
+- if (pipe(pipefd) < 0) {
+- crit(ap->logopt,
+- "failed to create commumication pipe for autofs path %s",
+- ap->path);
+- free(ap->path);
+- return -1;
+- }
+-
+- ap->pipefd = pipefd[0];
+- ap->kpipefd = pipefd[1];
+-
+- if ((cl_flags = fcntl(ap->pipefd, F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->pipefd, F_SETFD, cl_flags);
+- }
+-
+- if ((cl_flags = fcntl(ap->kpipefd, F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->kpipefd, F_SETFD, cl_flags);
+- }
+-
+- /* Pipe state changes from signal handler to main loop */
+- if (pipe(ap->state_pipe) < 0) {
+- crit(ap->logopt,
+- "failed create state pipe for autofs path %s", ap->path);
+- close(ap->pipefd);
+- close(ap->kpipefd); /* Close kernel pipe end */
+- free(ap->path);
+- return -1;
+- }
+-
+- if ((cl_flags = fcntl(ap->state_pipe[0], F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->state_pipe[0], F_SETFD, cl_flags);
+- }
+-
+- if ((cl_flags = fcntl(ap->state_pipe[1], F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(ap->state_pipe[1], F_SETFD, cl_flags);
+- }
+-
+- return 0;
+-}
+-
+ static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
+ {
+ struct mnt_list *this;
+@@ -118,7 +61,7 @@ static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
+ }
+
+ if (strcmp(this->fs_type, "autofs"))
+- rv = spawn_umount(log_debug, "-l", this->path, NULL);
++ rv = spawn_umount(ap->logopt, "-l", this->path, NULL);
+ else
+ rv = umount2(this->path, MNT_DETACH);
+ if (rv == -1) {
+@@ -222,12 +165,14 @@ static int do_mount_autofs_indirect(struct autofs_point *ap)
+ ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
+
+ if (ap->exp_timeout)
+- msg("mounted indirect mount on %s "
++ info(ap->logopt,
++ "mounted indirect mount on %s "
+ "with timeout %u, freq %u seconds", ap->path,
+- (unsigned int) ap->exp_timeout,
+- (unsigned int) ap->exp_runfreq);
++ (unsigned int) ap->exp_timeout,
++ (unsigned int) ap->exp_runfreq);
+ else
+- msg("mounted indirect mount on %s with timeouts disabled",
++ info(ap->logopt,
++ "mounted indirect mount on %s with timeouts disabled",
+ ap->path);
+
+ fstat(ap->ioctlfd, &st);
+@@ -257,9 +202,6 @@ int mount_autofs_indirect(struct autofs_point *ap)
+ int status;
+ int map;
+
+- if (autofs_init_indirect(ap))
+- return -1;
+-
+ /* TODO: read map, determine map type is OK */
+ if (lookup_nss_read_map(ap, NULL, now))
+ lookup_prune_cache(ap, now);
+@@ -309,7 +251,7 @@ int umount_autofs_indirect(struct autofs_point *ap)
+ rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
+ if (rv == -1) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, "ioctl failed: %s", estr);
++ logerr("ioctl failed: %s", estr);
+ return 1;
+ } else if (!ret) {
+ error(ap->logopt, "ask umount returned busy %s", ap->path);
+@@ -370,9 +312,9 @@ force_umount:
+ "forcing umount of indirect mount %s", ap->path);
+ rv = umount2(ap->path, MNT_DETACH);
+ } else {
+- msg("umounted indirect mount %s", ap->path);
++ info(ap->logopt, "umounted indirect mount %s", ap->path);
+ if (ap->submount)
+- rm_unwanted(ap->path, 1, ap->dev);
++ rm_unwanted(ap->logopt, ap->path, 1, ap->dev);
+ }
+
+ return rv;
+@@ -390,7 +332,7 @@ static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *pat
+ return 0;
+ }
+
+- retries = (count_mounts(path, st.st_dev) + 1) * EXPIRE_RETRIES;
++ retries = (count_mounts(ap->logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
+
+ while (retries--) {
+ struct timespec tm = {0, 100000000};
+@@ -559,13 +501,7 @@ void *expire_proc_indirect(void *arg)
+ * words) the umounts are done by the time we reach here
+ */
+ if (count)
+- debug(ap->logopt, "%d remaining in %s", count, ap->path);
+-
+- /* If we are trying to shutdown make sure we can umount */
+- if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
+- if (!ret)
+- msg("mount still busy %s", ap->path);
+- }
++ info(ap->logopt, "%d remaining in %s", count, ap->path);
+
+ ec.status = left;
+
+@@ -590,7 +526,7 @@ static void pending_cond_destroy(void *arg)
+ static void expire_send_fail(void *arg)
+ {
+ struct pending_args *mt = arg;
+- send_fail(mt->ap->ioctlfd, mt->wait_queue_token);
++ send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
+ }
+
+ static void free_pending_args(void *arg)
+@@ -634,9 +570,9 @@ static void *do_expire_indirect(void *arg)
+ status = do_expire(mt->ap, mt->name, mt->len);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
+ if (status)
+- send_fail(ap->ioctlfd, mt->wait_queue_token);
++ send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+ else
+- send_ready(ap->ioctlfd, mt->wait_queue_token);
++ send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+ pthread_setcancelstate(state, NULL);
+
+ pthread_cleanup_pop(0);
+@@ -661,8 +597,8 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_
+ mt = malloc(sizeof(struct pending_args));
+ if (!mt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, "malloc: %s", estr);
+- send_fail(ap->ioctlfd, pkt->wait_queue_token);
++ logerr("malloc: %s", estr);
++ send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ pthread_setcancelstate(state, NULL);
+ return 1;
+ }
+@@ -684,7 +620,7 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_
+ status = pthread_create(&thid, &thread_attr, do_expire_indirect, mt);
+ if (status) {
+ error(ap->logopt, "expire thread create failed");
+- send_fail(ap->ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ expire_mutex_unlock(NULL);
+ pending_cond_destroy(mt);
+ free_pending_args(mt);
+@@ -710,7 +646,7 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_
+ static void mount_send_fail(void *arg)
+ {
+ struct pending_args *mt = arg;
+- send_fail(mt->ap->ioctlfd, mt->wait_queue_token);
++ send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
+ }
+
+ static void mount_mutex_unlock(void *arg)
+@@ -775,7 +711,7 @@ static void *do_mount_indirect(void *arg)
+
+ pthread_setcancelstate(state, NULL);
+
+- msg("attempting to mount entry %s", buf);
++ info(ap->logopt, "attempting to mount entry %s", buf);
+
+ /*
+ * Setup thread specific data values for macro
+@@ -887,11 +823,11 @@ cont:
+ status = lookup_nss_mount(ap, NULL, mt->name, mt->len);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
+ if (status) {
+- send_ready(ap->ioctlfd, mt->wait_queue_token);
+- msg("mounted %s", buf);
++ send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
++ info(ap->logopt, "mounted %s", buf);
+ } else {
+- send_fail(ap->ioctlfd, mt->wait_queue_token);
+- msg("failed to mount %s", buf);
++ send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
++ info(ap->logopt, "failed to mount %s", buf);
+ }
+ pthread_setcancelstate(state, NULL);
+
+@@ -918,7 +854,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin
+ if (ap->state == ST_SHUTDOWN_PENDING ||
+ ap->state == ST_SHUTDOWN_FORCE ||
+ ap->state == ST_SHUTDOWN) {
+- send_fail(ap->ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ pthread_setcancelstate(state, NULL);
+ return 0;
+ }
+@@ -926,8 +862,8 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin
+ mt = malloc(sizeof(struct pending_args));
+ if (!mt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, "malloc: %s", estr);
+- send_fail(ap->ioctlfd, pkt->wait_queue_token);
++ logerr("malloc: %s", estr);
++ send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ pthread_setcancelstate(state, NULL);
+ return 1;
+ }
+@@ -953,7 +889,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin
+ status = pthread_create(&thid, &thread_attr, do_mount_indirect, mt);
+ if (status) {
+ error(ap->logopt, "expire thread create failed");
+- send_fail(ap->ioctlfd, pkt->wait_queue_token);
++ send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ mount_mutex_unlock(NULL);
+ pending_cond_destroy(mt);
+ free_pending_args(mt);
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 4f2b318..fd99cf2 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -103,6 +103,7 @@ static int do_read_master(struct master *master, char *type, time_t age)
+
+ static int read_master_map(struct master *master, char *type, time_t age)
+ {
++ unsigned int logopt = master->logopt;
+ char *path, *save_name;
+ int result;
+
+@@ -117,7 +118,7 @@ static int read_master_map(struct master *master, char *type, time_t age)
+ */
+
+ if (strchr(master->name, '/')) {
+- error(LOGOPT_ANY, "relative path invalid in files map name");
++ error(logopt, "relative path invalid in files map name");
+ return NSS_STATUS_NOTFOUND;
+ }
+
+@@ -142,6 +143,7 @@ static int read_master_map(struct master *master, char *type, time_t age)
+
+ int lookup_nss_read_master(struct master *master, time_t age)
+ {
++ unsigned int logopt = master->logopt;
+ struct list_head nsslist;
+ struct list_head *head, *p;
+ int result = NSS_STATUS_UNKNOWN;
+@@ -149,12 +151,10 @@ int lookup_nss_read_master(struct master *master, time_t age)
+ /* If it starts with a '/' it has to be a file or LDAP map */
+ if (*master->name == '/') {
+ if (*(master->name + 1) == '/') {
+- debug(LOGOPT_NONE,
+- "reading master ldap %s", master->name);
++ debug(logopt, "reading master ldap %s", master->name);
+ result = do_read_master(master, "ldap", age);
+ } else {
+- debug(LOGOPT_NONE,
+- "reading master file %s", master->name);
++ debug(logopt, "reading master file %s", master->name);
+ result = do_read_master(master, "file", age);
+ }
+
+@@ -184,13 +184,11 @@ int lookup_nss_read_master(struct master *master, time_t age)
+ */
+ if (strncmp(name, "ldap", 4)) {
+ master->name = tmp + 1;
+- debug(LOGOPT_NONE,
+- "reading master %s %s",
++ debug(logopt, "reading master %s %s",
+ source, master->name);
+ } else {
+ master->name = name;
+- debug(LOGOPT_NONE,
+- "reading master %s %s",
++ debug(logopt, "reading master %s %s",
+ source, tmp + 1);
+ }
+
+@@ -208,7 +206,7 @@ int lookup_nss_read_master(struct master *master, time_t age)
+ if (result) {
+ if (!list_empty(&nsslist))
+ free_sources(&nsslist);
+- error(LOGOPT_ANY, "can't to read name service switch config.");
++ error(logopt, "can't to read name service switch config.");
+ return 0;
+ }
+
+@@ -220,13 +218,12 @@ int lookup_nss_read_master(struct master *master, time_t age)
+
+ this = list_entry(p, struct nss_source, list);
+
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ "reading master %s %s", this->source, master->name);
+
+ result = read_master_map(master, this->source, age);
+ if (result == NSS_STATUS_UNKNOWN) {
+- debug(LOGOPT_NONE,
+- "no map - continuing to next source");
++ debug(logopt, "no map - continuing to next source");
+ continue;
+ }
+
+@@ -1008,9 +1005,10 @@ int lookup_prune_cache(struct autofs_point *ap, time_t age)
+ if (this->ioctlfd == -1)
+ status = cache_delete(mc, key);
+ if (status != CHE_FAIL) {
+- if (ap->type == LKP_INDIRECT)
+- rmdir_path(ap, path, ap->dev);
+- else
++ if (ap->type == LKP_INDIRECT) {
++ if (ap->ghost)
++ rmdir_path(ap, path, ap->dev);
++ } else
+ rmdir_path(ap, path, this->dev);
+ }
+ }
+diff --git a/daemon/module.c b/daemon/module.c
+index e83c929..36eca00 100644
+--- a/daemon/module.c
++++ b/daemon/module.c
+@@ -33,7 +33,7 @@ int load_autofs4_module(void)
+ */
+ fp = fopen("/proc/filesystems", "r");
+ if (!fp) {
+- error(LOGOPT_ANY, "cannot open /proc/filesystems\n");
++ logerr("cannot open /proc/filesystems\n");
+ return 0;
+ }
+
+@@ -45,7 +45,7 @@ int load_autofs4_module(void)
+ }
+ fclose(fp);
+
+- ret = spawnl(log_debug, PATH_MODPROBE, PATH_MODPROBE,
++ ret = spawnl(LOGOPT_NONE, PATH_MODPROBE, PATH_MODPROBE,
+ "-q", FS_MODULE_NAME, NULL);
+ if (ret)
+ return 0;
+@@ -72,7 +72,7 @@ struct lookup_mod *open_lookup(const char *name, const char *err_prefix,
+ if (!mod) {
+ if (err_prefix) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, "%s%s", err_prefix, estr);
++ logerr("%s%s", err_prefix, estr);
+ }
+ return NULL;
+ }
+@@ -83,7 +83,7 @@ struct lookup_mod *open_lookup(const char *name, const char *err_prefix,
+ free(mod);
+ if (err_prefix) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, "%s%s", err_prefix, estr);
++ logerr("%s%s", err_prefix, estr);
+ }
+ return NULL;
+ }
+@@ -91,7 +91,7 @@ struct lookup_mod *open_lookup(const char *name, const char *err_prefix,
+
+ if (!(dh = dlopen(fnbuf, RTLD_NOW))) {
+ if (err_prefix)
+- crit(LOGOPT_ANY, "%scannot open lookup module %s (%s)",
++ logerr("%scannot open lookup module %s (%s)",
+ err_prefix, name, dlerror());
+ free(mod);
+ return NULL;
+@@ -100,8 +100,7 @@ struct lookup_mod *open_lookup(const char *name, const char *err_prefix,
+ if (!(ver = (int *) dlsym(dh, "lookup_version"))
+ || *ver != AUTOFS_LOOKUP_VERSION) {
+ if (err_prefix)
+- crit(LOGOPT_ANY,
+- "%slookup module %s version mismatch",
++ logerr("%slookup module %s version mismatch",
+ err_prefix, name);
+ dlclose(dh);
+ free(mod);
+@@ -114,7 +113,7 @@ struct lookup_mod *open_lookup(const char *name, const char *err_prefix,
+ !(mod->lookup_mount = (lookup_mount_t) dlsym(dh, "lookup_mount")) ||
+ !(mod->lookup_done = (lookup_done_t) dlsym(dh, "lookup_done"))) {
+ if (err_prefix)
+- crit(LOGOPT_ANY, "%slookup module %s corrupt", err_prefix, name);
++ logerr("%slookup module %s corrupt", err_prefix, name);
+ dlclose(dh);
+ free(mod);
+ return NULL;
+@@ -156,7 +155,7 @@ struct parse_mod *open_parse(const char *name, const char *err_prefix,
+ if (!mod) {
+ if (err_prefix) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, "%s%s", err_prefix, estr);
++ logerr("%s%s", err_prefix, estr);
+ }
+ return NULL;
+ }
+@@ -167,7 +166,7 @@ struct parse_mod *open_parse(const char *name, const char *err_prefix,
+ free(mod);
+ if (err_prefix) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, "%s%s", err_prefix, estr);
++ logerr("%s%s", err_prefix, estr);
+ }
+ return NULL;
+ }
+@@ -175,8 +174,7 @@ struct parse_mod *open_parse(const char *name, const char *err_prefix,
+
+ if (!(dh = dlopen(fnbuf, RTLD_NOW))) {
+ if (err_prefix)
+- crit(LOGOPT_ANY,
+- "%scannot open parse module %s (%s)",
++ logerr("%scannot open parse module %s (%s)",
+ err_prefix, name, dlerror());
+ free(mod);
+ return NULL;
+@@ -185,8 +183,7 @@ struct parse_mod *open_parse(const char *name, const char *err_prefix,
+ if (!(ver = (int *) dlsym(dh, "parse_version"))
+ || *ver != AUTOFS_PARSE_VERSION) {
+ if (err_prefix)
+- crit(LOGOPT_ANY,
+- "%sparse module %s version mismatch",
++ logerr("%sparse module %s version mismatch",
+ err_prefix, name);
+ dlclose(dh);
+ free(mod);
+@@ -197,8 +194,7 @@ struct parse_mod *open_parse(const char *name, const char *err_prefix,
+ !(mod->parse_mount = (parse_mount_t) dlsym(dh, "parse_mount")) ||
+ !(mod->parse_done = (parse_done_t) dlsym(dh, "parse_done"))) {
+ if (err_prefix)
+- crit(LOGOPT_ANY,
+- "%sparse module %s corrupt",
++ logerr("%sparse module %s corrupt",
+ err_prefix, name);
+ dlclose(dh);
+ free(mod);
+@@ -240,7 +236,7 @@ struct mount_mod *open_mount(const char *name, const char *err_prefix)
+ if (!mod) {
+ if (err_prefix) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, "%s%s", err_prefix, estr);
++ logerr("%s%s", err_prefix, estr);
+ }
+ return NULL;
+ }
+@@ -251,7 +247,7 @@ struct mount_mod *open_mount(const char *name, const char *err_prefix)
+ free(mod);
+ if (err_prefix) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, "%s%s", err_prefix, estr);
++ logerr("%s%s", err_prefix, estr);
+ }
+ return NULL;
+ }
+@@ -259,8 +255,7 @@ struct mount_mod *open_mount(const char *name, const char *err_prefix)
+
+ if (!(dh = dlopen(fnbuf, RTLD_NOW))) {
+ if (err_prefix)
+- crit(LOGOPT_ANY,
+- "%scannot open mount module %s (%s)",
++ logerr("%scannot open mount module %s (%s)",
+ err_prefix, name, dlerror());
+ free(mod);
+ return NULL;
+@@ -269,8 +264,7 @@ struct mount_mod *open_mount(const char *name, const char *err_prefix)
+ if (!(ver = (int *) dlsym(dh, "mount_version"))
+ || *ver != AUTOFS_MOUNT_VERSION) {
+ if (err_prefix)
+- crit(LOGOPT_ANY,
+- "%smount module %s version mismatch",
++ logerr("%smount module %s version mismatch",
+ err_prefix, name);
+ dlclose(dh);
+ free(mod);
+@@ -281,8 +275,7 @@ struct mount_mod *open_mount(const char *name, const char *err_prefix)
+ !(mod->mount_mount = (mount_mount_t) dlsym(dh, "mount_mount")) ||
+ !(mod->mount_done = (mount_done_t) dlsym(dh, "mount_done"))) {
+ if (err_prefix)
+- crit(LOGOPT_ANY,
+- "%smount module %s corrupt",
++ logerr("%smount module %s corrupt",
+ err_prefix, name);
+ dlclose(dh);
+ free(mod);
+diff --git a/daemon/spawn.c b/daemon/spawn.c
+index 271d37e..3d5ea56 100644
+--- a/daemon/spawn.c
++++ b/daemon/spawn.c
+@@ -88,7 +88,7 @@ void reset_signals(void)
+
+ #define ERRBUFSIZ 2047 /* Max length of error string excl \0 */
+
+-static int do_spawn(logger *log, unsigned int options, const char *prog, const char *const *argv)
++static int do_spawn(unsigned logopt, unsigned int options, const char *prog, const char *const *argv)
+ {
+ pid_t f;
+ int ret, status, pipefd[2];
+@@ -195,7 +195,7 @@ static int do_spawn(logger *log, unsigned int options, const char *prog, const c
+ while (errp && (p = memchr(sp, '\n', errp))) {
+ *p++ = '\0';
+ if (sp[0]) /* Don't output empty lines */
+- log(LOGOPT_ANY, ">> %s", sp);
++ warn(logopt, ">> %s", sp);
+ errp -= (p - sp);
+ sp = p;
+ }
+@@ -206,7 +206,7 @@ static int do_spawn(logger *log, unsigned int options, const char *prog, const c
+ if (errp >= ERRBUFSIZ) {
+ /* Line too long, split */
+ errbuf[errp] = '\0';
+- log(LOGOPT_ANY, ">> %s", errbuf);
++ warn(logopt, ">> %s", errbuf);
+ errp = 0;
+ }
+ }
+@@ -217,7 +217,7 @@ static int do_spawn(logger *log, unsigned int options, const char *prog, const c
+ if (errp > 0) {
+ /* End of file without \n */
+ errbuf[errp] = '\0';
+- log(LOGOPT_ANY, ">> %s", errbuf);
++ warn(logopt, ">> %s", errbuf);
+ }
+
+ if (waitpid(f, &ret, 0) != f)
+@@ -235,12 +235,12 @@ static int do_spawn(logger *log, unsigned int options, const char *prog, const c
+ }
+ }
+
+-int spawnv(logger *log, const char *prog, const char *const *argv)
++int spawnv(unsigned logopt, const char *prog, const char *const *argv)
+ {
+- return do_spawn(log, SPAWN_OPT_NONE, prog, argv);
++ return do_spawn(logopt, SPAWN_OPT_NONE, prog, argv);
+ }
+
+-int spawnl(logger *log, const char *prog, ...)
++int spawnl(unsigned logopt, const char *prog, ...)
+ {
+ va_list arg;
+ int argc;
+@@ -258,10 +258,10 @@ int spawnl(logger *log, const char *prog, ...)
+ while ((*p++ = va_arg(arg, char *)));
+ va_end(arg);
+
+- return do_spawn(log, SPAWN_OPT_NONE, prog, (const char **) argv);
++ return do_spawn(logopt, SPAWN_OPT_NONE, prog, (const char **) argv);
+ }
+
+-int spawn_mount(logger *log, ...)
++int spawn_mount(unsigned logopt, ...)
+ {
+ va_list arg;
+ int argc;
+@@ -279,7 +279,7 @@ int spawn_mount(logger *log, ...)
+ options = SPAWN_OPT_NONE;
+ #endif
+
+- va_start(arg, log);
++ va_start(arg, logopt);
+ for (argc = 1; va_arg(arg, char *); argc++);
+ va_end(arg);
+
+@@ -288,13 +288,13 @@ int spawn_mount(logger *log, ...)
+
+ argv[0] = arg0;
+
+- va_start(arg, log);
++ va_start(arg, logopt);
+ p = argv + 1;
+ while ((*p++ = va_arg(arg, char *)));
+ va_end(arg);
+
+ while (retries--) {
+- ret = do_spawn(log, options, prog, (const char **) argv);
++ ret = do_spawn(logopt, options, prog, (const char **) argv);
+ if (ret & MTAB_NOTUPDATED)
+ continue;
+ break;
+@@ -311,7 +311,7 @@ int spawn_mount(logger *log, ...)
+ * NOTE: If mount locking is enabled this type of recursive mount cannot
+ * work.
+ */
+-int spawn_bind_mount(logger *log, ...)
++int spawn_bind_mount(unsigned logopt, ...)
+ {
+ va_list arg;
+ int argc;
+@@ -330,7 +330,7 @@ int spawn_bind_mount(logger *log, ...)
+ options = SPAWN_OPT_ACCESS;
+ #endif
+
+- va_start(arg, log);
++ va_start(arg, logopt);
+ for (argc = 1; va_arg(arg, char *); argc++);
+ va_end(arg);
+
+@@ -340,13 +340,13 @@ int spawn_bind_mount(logger *log, ...)
+ argv[0] = arg0;
+ argv[1] = bind;
+
+- va_start(arg, log);
++ va_start(arg, logopt);
+ p = argv + 2;
+ while ((*p++ = va_arg(arg, char *)));
+ va_end(arg);
+
+ while (retries--) {
+- ret = do_spawn(log, options, prog, (const char **) argv);
++ ret = do_spawn(logopt, options, prog, (const char **) argv);
+ if (ret & MTAB_NOTUPDATED)
+ continue;
+ break;
+@@ -355,7 +355,7 @@ int spawn_bind_mount(logger *log, ...)
+ return ret;
+ }
+
+-int spawn_umount(logger *log, ...)
++int spawn_umount(unsigned logopt, ...)
+ {
+ va_list arg;
+ int argc;
+@@ -372,7 +372,7 @@ int spawn_umount(logger *log, ...)
+ options = SPAWN_OPT_NONE;
+ #endif
+
+- va_start(arg, log);
++ va_start(arg, logopt);
+ for (argc = 1; va_arg(arg, char *); argc++);
+ va_end(arg);
+
+@@ -381,13 +381,13 @@ int spawn_umount(logger *log, ...)
+
+ argv[0] = arg0;
+
+- va_start(arg, log);
++ va_start(arg, logopt);
+ p = argv + 1;
+ while ((*p++ = va_arg(arg, char *)));
+ va_end(arg);
+
+ while (retries--) {
+- ret = do_spawn(log, options, prog, (const char **) argv);
++ ret = do_spawn(logopt, options, prog, (const char **) argv);
+ if (ret & MTAB_NOTUPDATED)
+ continue;
+ break;
+diff --git a/daemon/state.c b/daemon/state.c
+index 39f4497..a2da762 100644
+--- a/daemon/state.c
++++ b/daemon/state.c
+@@ -58,22 +58,20 @@ void dump_state_queue(void)
+ struct list_head *head = &state_queue;
+ struct list_head *p, *q;
+
+- debug(LOGOPT_ANY, "dumping queue");
++ logmsg("dumping queue");
+
+ list_for_each(p, head) {
+ struct state_queue *entry;
+
+ entry = list_entry(p, struct state_queue, list);
+- debug(LOGOPT_ANY,
+- "queue list head path %s state %d busy %d",
++ logmsg("queue list head path %s state %d busy %d",
+ entry->ap->path, entry->state, entry->busy);
+
+ list_for_each(q, &entry->pending) {
+ struct state_queue *this;
+
+ this = list_entry(q, struct state_queue, pending);
+- debug(LOGOPT_ANY,
+- "queue list entry path %s state %d busy %d",
++ logmsg("queue list entry path %s state %d busy %d",
+ this->ap->path, this->state, this->busy);
+ }
+ }
+@@ -85,7 +83,7 @@ void nextstate(int statefd, enum states next)
+
+ if (write(statefd, &next, sizeof(next)) != sizeof(next)) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "write failed %s", estr);
++ logerr("write failed %s", estr);
+ }
+ }
+
+diff --git a/include/automount.h b/include/automount.h
+index d55ba5c..37a3c0a 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -131,6 +131,7 @@ struct mapent_cache {
+ unsigned int size;
+ pthread_mutex_t ino_index_mutex;
+ struct list_head *ino_index;
++ struct autofs_point *ap;
+ struct map_source *map;
+ struct mapent **hash;
+ };
+@@ -164,7 +165,7 @@ void cache_readlock(struct mapent_cache *mc);
+ void cache_writelock(struct mapent_cache *mc);
+ int cache_try_writelock(struct mapent_cache *mc);
+ void cache_unlock(struct mapent_cache *mc);
+-struct mapent_cache *cache_init(struct map_source *map);
++struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map);
+ struct mapent_cache *cache_init_null_cache(struct master *master);
+ int cache_set_ino_index(struct mapent_cache *mc, const char *key, dev_t dev, ino_t ino);
+ /* void cache_set_ino(struct mapent *me, dev_t dev, ino_t ino); */
+@@ -200,11 +201,11 @@ int free_argv(int argc, const char **argv);
+ inline void dump_core(void);
+ int aquire_lock(void);
+ void release_lock(void);
+-int spawnl(logger *log, const char *prog, ...);
+-int spawnv(logger *log, const char *prog, const char *const *argv);
+-int spawn_mount(logger *log, ...);
+-int spawn_bind_mount(logger *log, ...);
+-int spawn_umount(logger *log, ...);
++int spawnl(unsigned logopt, const char *prog, ...);
++int spawnv(unsigned logopt, const char *prog, const char *const *argv);
++int spawn_mount(unsigned logopt, ...);
++int spawn_bind_mount(unsigned logopt, ...);
++int spawn_umount(unsigned logopt, ...);
+ void reset_signals(void);
+ int do_mount(struct autofs_point *ap, const char *root, const char *name,
+ int name_len, const char *what, const char *fstype,
+@@ -222,6 +223,8 @@ int rmdir_path(struct autofs_point *ap, const char *path, dev_t dev);
+ #define MAPENT_MAX_LEN 4095
+ #define PARSE_MAX_BUF KEY_MAX_LEN + MAPENT_MAX_LEN + 2
+
++#define AUTOFS_LOGPRI_FIFO "/tmp/autofs.fifo"
++
+ int lookup_nss_read_master(struct master *master, time_t age);
+ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age);
+ int lookup_enumerate(struct autofs_point *ap,
+@@ -435,6 +438,7 @@ struct autofs_point {
+ int pipefd; /* File descriptor for pipe */
+ int kpipefd; /* Kernel end descriptor for pipe */
+ int ioctlfd; /* File descriptor for ioctls */
++ int logpri_fifo; /* FIFO used for changing log levels */
+ dev_t dev; /* "Device" number assigned by kernel */
+ struct master_mapent *entry; /* Master map entry for this mount */
+ unsigned int type; /* Type of map direct or indirect */
+@@ -464,8 +468,8 @@ struct autofs_point {
+
+ void *handle_mounts(void *arg);
+ int umount_multi(struct autofs_point *ap, const char *path, int incl);
+-int send_ready(int ioctlfd, unsigned int wait_queue_token);
+-int send_fail(int ioctlfd, unsigned int wait_queue_token);
++int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token);
++int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token);
+ int do_expire(struct autofs_point *ap, const char *name, int namelen);
+ void *expire_proc_indirect(void *);
+ void *expire_proc_direct(void *);
+@@ -483,8 +487,8 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_
+ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_direct_t *pkt);
+ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missing_indirect_t *pkt);
+ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_direct_t *pkt);
+-void rm_unwanted(const char *path, int incl, dev_t dev);
+-int count_mounts(const char *path, dev_t dev);
++void rm_unwanted(unsigned logopt, const char *path, int incl, dev_t dev);
++int count_mounts(unsigned logopt, const char *path, dev_t dev);
+
+ #define state_mutex_lock(ap) \
+ do { \
+diff --git a/include/log.h b/include/log.h
+index 3276cca..6a4a942 100644
+--- a/include/log.h
++++ b/include/log.h
+@@ -20,6 +20,7 @@
+ /* Define logging functions */
+
+ #define LOGOPT_NONE 0x0000
++#define LOGOPT_ERROR 0x0000
+ #define LOGOPT_DEBUG 0x0001
+ #define LOGOPT_VERBOSE 0x0002
+ #define LOGOPT_ANY (LOGOPT_DEBUG | LOGOPT_VERBOSE)
+@@ -29,34 +30,33 @@ struct autofs_point;
+ extern void set_log_norm(void);
+ extern void set_log_verbose(void);
+ extern void set_log_debug(void);
+-extern void set_mnt_logging(struct autofs_point *);
++extern void set_log_norm_ap(struct autofs_point *ap);
++extern void set_log_verbose_ap(struct autofs_point *ap);
++extern void set_log_debug_ap(struct autofs_point *ap);
++extern void set_mnt_logging(unsigned global_logopt);
+
+ extern void log_to_syslog(void);
+ extern void log_to_stderr(void);
+
+-typedef void logger(unsigned int logopt, const char* msg, ...);
+-
+-extern void (*log_info)(unsigned int, const char* msg, ...);
+-extern void (*log_notice)(unsigned int, const char* msg, ...);
+-extern void (*log_warn)(unsigned int, const char* msg, ...);
+-extern void (*log_error)(unsigned int, const char* msg, ...);
+-extern void (*log_crit)(unsigned int, const char* msg, ...);
+-extern void (*log_debug)(unsigned int, const char* msg, ...);
+-
+-#define msg(msg, args...) \
+- do { log_info(LOGOPT_NONE, msg, ##args); } while (0)
++extern void log_info(unsigned int, const char* msg, ...);
++extern void log_notice(unsigned int, const char* msg, ...);
++extern void log_warn(unsigned int, const char* msg, ...);
++extern void log_error(unsigned, const char* msg, ...);
++extern void log_crit(unsigned, const char* msg, ...);
++extern void log_debug(unsigned int, const char* msg, ...);
++extern void logmsg(const char* msg, ...);
+
+ #define debug(opt, msg, args...) \
+ do { log_debug(opt, "%s: " msg, __FUNCTION__, ##args); } while (0)
+
+-#define info(opt, msg, args...) \
+- do { log_info(opt, "%s: " msg, __FUNCTION__, ##args); } while (0)
++#define info(opt, msg, args...) \
++ do { log_info(opt, msg, ##args); } while (0)
+
+ #define notice(opt, msg, args...) \
+- do { log_notice(opt, "%s: " msg, __FUNCTION__, ##args); } while (0)
++ do { log_notice(opt, msg, ##args); } while (0)
+
+-#define warn(opt, msg, args...) \
+- do { log_warn(opt, "%s: " msg, __FUNCTION__, ##args); } while (0)
++#define warn(opt, msg, args...) \
++ do { log_warn(opt, msg, ##args); } while (0)
+
+ #define error(opt, msg, args...) \
+ do { log_error(opt, "%s: " msg, __FUNCTION__, ##args); } while (0)
+@@ -64,17 +64,18 @@ extern void (*log_debug)(unsigned int, const char* msg, ...);
+ #define crit(opt, msg, args...) \
+ do { log_crit(opt, "%s: " msg, __FUNCTION__, ##args); } while (0)
+
++#define logerr(msg, args...) \
++ do { logmsg("%s:%d: " msg, __FUNCTION__, __LINE__, ##args); } while (0)
++
+ #define fatal(status) \
+ do { \
+ if (status == EDEADLK) { \
+- log_crit(LOGOPT_ANY, \
+- "%s: deadlock detected " \
++ logmsg("deadlock detected " \
+ "at line %d in %s, dumping core.", \
+- __FUNCTION__, __LINE__, __FILE__); \
++ __LINE__, __FILE__); \
+ dump_core(); \
+ } \
+- log_crit(LOGOPT_ANY, \
+- "unexpected pthreads error: %d at %d " \
++ logmsg("unexpected pthreads error: %d at %d " \
+ "in %s", status, __LINE__, __FILE__); \
+ abort(); \
+ } while(0)
+@@ -83,7 +84,7 @@ extern void (*log_debug)(unsigned int, const char* msg, ...);
+ #define assert(x) \
+ do { \
+ if (!(x)) { \
+- log_crit(LOGOPT_ANY, __FILE__ \
++ logmsg(__FILE__ \
+ ":%d: assertion failed: " #x, __LINE__); \
+ } \
+ } while(0)
+diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
+index ca8d658..5b5c475 100644
+--- a/include/lookup_ldap.h
++++ b/include/lookup_ldap.h
+@@ -94,13 +94,13 @@ struct lookup_context {
+ #define LDAP_AUTH_AUTODETECT 0x0004
+
+ /* lookup_ldap.c */
+-LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt);
+-int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt);
++LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt);
++int unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt);
+ int authtype_requires_creds(const char *authtype);
+
+ /* cyrus-sasl.c */
+-int autofs_sasl_init(LDAP *ldap, struct lookup_context *ctxt);
+-int autofs_sasl_bind(LDAP *ldap, struct lookup_context *ctxt);
++int autofs_sasl_init(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt);
++int autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt);
+ void autofs_sasl_unbind(struct lookup_context *ctxt);
+ void autofs_sasl_done(struct lookup_context *ctxt);
+ #endif
+diff --git a/include/master.h b/include/master.h
+index 8470bb1..5f10d1f 100644
+--- a/include/master.h
++++ b/include/master.h
+@@ -62,6 +62,7 @@ struct master {
+ unsigned int default_ghost;
+ unsigned int default_logging;
+ unsigned int default_timeout;
++ unsigned int logopt;
+ struct mapent_cache *nc;
+ struct list_head mounts;
+ };
+@@ -106,6 +107,7 @@ int master_notify_submount(struct autofs_point *, const char *path, enum states)
+ void master_signal_submount(struct autofs_point *, unsigned int);
+ void master_notify_state_change(struct master *, int);
+ int master_mount_mounts(struct master *, time_t, int);
++extern inline unsigned int master_get_logopt(void);
+ int master_list_empty(struct master *);
+ int master_kill(struct master *);
+
+diff --git a/include/replicated.h b/include/replicated.h
+index 3afe9f7..672f853 100644
+--- a/include/replicated.h
++++ b/include/replicated.h
+@@ -62,8 +62,8 @@ struct host {
+
+ void seed_random(void);
+ void free_host_list(struct host **);
+-int parse_location(struct host **, const char *);
+-int prune_host_list(struct host **, unsigned int, const char *, unsigned int);
++int parse_location(unsigned, struct host **, const char *);
++int prune_host_list(unsigned, struct host **, unsigned int, const char *, unsigned int);
+ void dump_host_list(struct host *);
+
+ #endif
+diff --git a/lib/alarm.c b/lib/alarm.c
+index 90bf7aa..6a70ed1 100755
+--- a/lib/alarm.c
++++ b/lib/alarm.c
+@@ -51,7 +51,7 @@ void dump_alarms(void)
+ struct alarm *this;
+
+ this = list_entry(p, struct alarm, list);
+- msg("alarm time = %d", this->time);
++ logmsg("alarm time = %d", this->time);
+ }
+ pthread_mutex_unlock(&mutex);
+ }
+diff --git a/lib/args.c b/lib/args.c
+index fbfb004..9616598 100644
+--- a/lib/args.c
++++ b/lib/args.c
+@@ -37,7 +37,7 @@ char **add_argv(int argc, char **argv, char *str)
+ if (argv[i]) {
+ vector[i] = strdup(argv[i]);
+ if (!vector[i]) {
+- error(LOGOPT_ANY, "failed to strdup arg");
++ logerr("failed to strdup arg");
+ break;
+ }
+ } else
+@@ -81,7 +81,7 @@ char **append_argv(int argc1, char **argv1, int argc2, char **argv2)
+ if (argv2[j]) {
+ vector[i] = strdup(argv2[j]);
+ if (!vector[i]) {
+- error(LOGOPT_ANY, "failed to strdup arg");
++ logerr("failed to strdup arg");
+ break;
+ }
+ } else
+@@ -116,7 +116,7 @@ const char **copy_argv(int argc, const char **argv)
+ if (argv[i]) {
+ vector[i] = strdup(argv[i]);
+ if (!vector[i]) {
+- error(LOGOPT_ANY, "failed to strdup arg");
++ logerr("failed to strdup arg");
+ break;
+ }
+ } else
+diff --git a/lib/cache.c b/lib/cache.c
+index 06bb461..55586a3 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -34,7 +34,7 @@ void cache_dump_multi(struct list_head *list)
+
+ list_for_each(p, list) {
+ me = list_entry(p, struct mapent, multi_list);
+- msg("key=%s", me->key);
++ logmsg("key=%s", me->key);
+ }
+ }
+
+@@ -48,7 +48,7 @@ void cache_dump_cache(struct mapent_cache *mc)
+ if (me == NULL)
+ continue;
+ while (me) {
+- msg("me->key=%s me->multi=%p dev=%ld ino=%ld",
++ logmsg("me->key=%s me->multi=%p dev=%ld ino=%ld",
+ me->key, me->multi, me->dev, me->ino);
+ me = me->next;
+ }
+@@ -61,7 +61,7 @@ void cache_readlock(struct mapent_cache *mc)
+
+ status = pthread_rwlock_rdlock(&mc->rwlock);
+ if (status) {
+- error(LOGOPT_ANY, "mapent cache rwlock lock failed");
++ logmsg("mapent cache rwlock lock failed");
+ fatal(status);
+ }
+ return;
+@@ -73,7 +73,7 @@ void cache_writelock(struct mapent_cache *mc)
+
+ status = pthread_rwlock_wrlock(&mc->rwlock);
+ if (status) {
+- error(LOGOPT_ANY, "mapent cache rwlock lock failed");
++ logmsg("mapent cache rwlock lock failed");
+ fatal(status);
+ }
+ return;
+@@ -85,7 +85,7 @@ int cache_try_writelock(struct mapent_cache *mc)
+
+ status = pthread_rwlock_trywrlock(&mc->rwlock);
+ if (status) {
+- debug(LOGOPT_ANY, "mapent cache rwlock busy");
++ logmsg("mapent cache rwlock busy");
+ return 0;
+ }
+ return 1;
+@@ -97,7 +97,7 @@ void cache_unlock(struct mapent_cache *mc)
+
+ status = pthread_rwlock_unlock(&mc->rwlock);
+ if (status) {
+- error(LOGOPT_ANY, "mapent cache rwlock unlock failed");
++ logmsg("mapent cache rwlock unlock failed");
+ fatal(status);
+ }
+ return;
+@@ -120,7 +120,7 @@ void cache_multi_lock(struct mapent *me)
+
+ status = pthread_mutex_lock(&me->multi_mutex);
+ if (status) {
+- error(LOGOPT_ANY, "mapent cache multi mutex lock failed");
++ logmsg("mapent cache multi mutex lock failed");
+ fatal(status);
+ }
+ return;
+@@ -135,7 +135,7 @@ void cache_multi_unlock(struct mapent *me)
+
+ status = pthread_mutex_unlock(&me->multi_mutex);
+ if (status) {
+- error(LOGOPT_ANY, "mapent cache multi mutex unlock failed");
++ logmsg("mapent cache multi mutex unlock failed");
+ fatal(status);
+ }
+ return;
+@@ -164,7 +164,7 @@ static inline void ino_index_unlock(struct mapent_cache *mc)
+ return;
+ }
+
+-struct mapent_cache *cache_init(struct map_source *map)
++struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map)
+ {
+ struct mapent_cache *mc;
+ unsigned int i;
+@@ -207,6 +207,7 @@ struct mapent_cache *cache_init(struct map_source *map)
+ INIT_LIST_HEAD(&mc->ino_index[i]);
+ }
+
++ mc->ap = ap;
+ mc->map = map;
+
+ cache_unlock(mc);
+@@ -257,6 +258,9 @@ struct mapent_cache *cache_init_null_cache(struct master *master)
+ INIT_LIST_HEAD(&mc->ino_index[i]);
+ }
+
++ mc->ap = NULL;
++ mc->map = NULL;
++
+ cache_unlock(mc);
+
+ return mc;
+@@ -608,6 +612,7 @@ static void cache_add_ordered_offset(struct mapent *me, struct list_head *head)
+ /* cache must be write locked by caller */
+ int cache_add_offset(struct mapent_cache *mc, const char *mkey, const char *key, const char *mapent, time_t age)
+ {
++ unsigned logopt = mc->ap ? mc->ap->logopt : master_get_logopt();
+ struct mapent *me, *owner;
+ int ret = CHE_OK;
+
+@@ -621,7 +626,7 @@ int cache_add_offset(struct mapent_cache *mc, const char *mkey, const char *key,
+
+ ret = cache_add(mc, owner->source, key, mapent, age);
+ if (ret == CHE_FAIL) {
+- warn(LOGOPT_ANY, "failed to add key %s to cache", key);
++ warn(logopt, "failed to add key %s to cache", key);
+ return CHE_FAIL;
+ }
+
+@@ -689,6 +694,7 @@ int cache_set_parents(struct mapent *mm)
+ /* cache must be write locked by caller */
+ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age)
+ {
++ unsigned logopt = mc->ap ? mc->ap->logopt : master_get_logopt();
+ struct mapent *me = NULL;
+ char *pent;
+ int ret = CHE_OK;
+@@ -697,7 +703,7 @@ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key
+ if (!me || (*me->key == '*' && *key != '*')) {
+ ret = cache_add(mc, ms, key, mapent, age);
+ if (!ret) {
+- debug(LOGOPT_NONE, "failed for %s", key);
++ debug(logopt, "failed for %s", key);
+ return CHE_FAIL;
+ }
+ ret = CHE_UPDATED;
+@@ -796,6 +802,7 @@ done:
+ /* cache must be write locked by caller */
+ int cache_delete_offset_list(struct mapent_cache *mc, const char *key)
+ {
++ unsigned logopt = mc->ap ? mc->ap->logopt : master_get_logopt();
+ struct mapent *me;
+ struct mapent *this;
+ struct list_head *head, *next;
+@@ -816,7 +823,7 @@ int cache_delete_offset_list(struct mapent_cache *mc, const char *key)
+ this = list_entry(next, struct mapent, multi_list);
+ next = next->next;
+ if (this->ioctlfd != -1) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "active offset mount key %s", this->key);
+ return CHE_FAIL;
+ }
+@@ -829,10 +836,10 @@ int cache_delete_offset_list(struct mapent_cache *mc, const char *key)
+ next = next->next;
+ list_del_init(&this->multi_list);
+ this->multi = NULL;
+- debug(LOGOPT_NONE, "deleting offset key %s", this->key);
++ debug(logopt, "deleting offset key %s", this->key);
+ status = cache_delete(mc, this->key);
+ if (status == CHE_FAIL) {
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ "failed to delete offset %s", this->key);
+ this->multi = me;
+ /* TODO: add list back in */
+diff --git a/lib/defaults.c b/lib/defaults.c
+index 2cccf20..94885e8 100644
+--- a/lib/defaults.c
++++ b/lib/defaults.c
+@@ -105,17 +105,22 @@ static int get_env_yesno(const char *name)
+ * We've changed the key names so we need to check for the
+ * config key and it's old name for backward conpatibility.
+ */
+-static int check_set_config_value(const char *res, const char *name, const char *value)
++static int check_set_config_value(const char *res, const char *name, const char *value, unsigned to_syslog)
+ {
+ char *old_name;
+ int ret;
+
+ if (!strcasecmp(res, name)) {
+ ret = setenv(name, value, 0);
+- if (ret)
+- fprintf(stderr,
+- "can't set config value for %s, "
+- "error %d", name, ret);
++ if (ret) {
++ if (!to_syslog)
++ fprintf(stderr,
++ "can't set config value for %s, "
++ "error %d\n", name, ret);
++ else
++ logmsg("can't set config value for %s, "
++ "error %d", name, ret);
++ }
+ return 1;
+ }
+
+@@ -125,10 +130,15 @@ static int check_set_config_value(const char *res, const char *name, const char
+
+ if (!strcasecmp(res, old_name)) {
+ ret = setenv(name, value, 0);
+- if (ret)
+- fprintf(stderr,
+- "can't set config value for %s, "
+- "error %d", name, ret);
++ if (ret) {
++ if (!to_syslog)
++ fprintf(stderr,
++ "can't set config value for %s, "
++ "error %d\n", name, ret);
++ else
++ logmsg("can't set config value for %s, "
++ "error %d\n", name, ret);
++ }
+ return 1;
+ }
+ return 0;
+@@ -296,19 +306,19 @@ unsigned int defaults_read_config(unsigned int to_syslog)
+ if (!parse_line(res, &key, &value))
+ continue;
+
+- if (check_set_config_value(key, ENV_NAME_MASTER_MAP, value) ||
+- check_set_config_value(key, ENV_NAME_TIMEOUT, value) ||
+- check_set_config_value(key, ENV_NAME_BROWSE_MODE, value) ||
+- check_set_config_value(key, ENV_NAME_LOGGING, value) ||
+- check_set_config_value(key, ENV_LDAP_TIMEOUT, value) ||
+- check_set_config_value(key, ENV_LDAP_NETWORK_TIMEOUT, value) ||
+- check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value) ||
+- check_set_config_value(key, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
+- check_set_config_value(key, ENV_NAME_MAP_ATTR, value) ||
+- check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value) ||
+- check_set_config_value(key, ENV_NAME_VALUE_ATTR, value) ||
+- check_set_config_value(key, ENV_APPEND_OPTIONS, value) ||
+- check_set_config_value(key, ENV_AUTH_CONF_FILE, value))
++ if (check_set_config_value(key, ENV_NAME_MASTER_MAP, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_TIMEOUT, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_BROWSE_MODE, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_LOGGING, value, to_syslog) ||
++ check_set_config_value(key, ENV_LDAP_TIMEOUT, value, to_syslog) ||
++ check_set_config_value(key, ENV_LDAP_NETWORK_TIMEOUT, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_ENTRY_OBJ_CLASS, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_MAP_ATTR, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_VALUE_ATTR, value, to_syslog) ||
++ check_set_config_value(key, ENV_APPEND_OPTIONS, value, to_syslog) ||
++ check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog))
+ ;
+ }
+
+@@ -318,8 +328,7 @@ unsigned int defaults_read_config(unsigned int to_syslog)
+ "fgets returned error %d while reading %s\n",
+ ferror(f), DEFAULTS_CONFIG_FILE);
+ } else {
+- error(LOGOPT_ANY,
+- "fgets returned error %d while reading %s",
++ logmsg("fgets returned error %d while reading %s",
+ ferror(f), DEFAULTS_CONFIG_FILE);
+ }
+ fclose(f);
+diff --git a/lib/log.c b/lib/log.c
+index b747e12..65e8ad2 100644
+--- a/lib/log.c
++++ b/lib/log.c
+@@ -27,11 +27,6 @@
+
+ #include "automount.h"
+
+-/*
+-struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+-struct syslog_data *slc = &syslog_context;
+-*/
+-
+ static unsigned int syslog_open = 0;
+ static unsigned int logging_to_syslog = 0;
+
+@@ -39,32 +34,44 @@ static unsigned int logging_to_syslog = 0;
+ static unsigned int do_verbose = 0; /* Verbose feedback option */
+ static unsigned int do_debug = 0; /* Full debug output */
+
+-static void null(unsigned int logopt, const char *msg, ...) { }
+-
+-void (*log_info)(unsigned int logopt, const char* msg, ...) = null;
+-void (*log_notice)(unsigned int logopt, const char* msg, ...) = null;
+-void (*log_warn)(unsigned int logopt, const char* msg, ...) = null;
+-void (*log_error)(unsigned int logopt, const char* msg, ...) = null;
+-void (*log_crit)(unsigned int logopt, const char* msg, ...) = null;
+-void (*log_debug)(unsigned int logopt, const char* msg, ...) = null;
+-
+ void set_log_norm(void)
+ {
+ do_verbose = 0;
+ do_debug = 0;
++ return;
+ }
+
+ void set_log_verbose(void)
+ {
+ do_verbose = 1;
++ return;
+ }
+
+ void set_log_debug(void)
+ {
+ do_debug = 1;
++ return;
++}
++
++void set_log_norm_ap(struct autofs_point *ap)
++{
++ ap->logopt = LOGOPT_ERROR;
++ return;
++}
++
++void set_log_verbose_ap(struct autofs_point *ap)
++{
++ ap->logopt = LOGOPT_VERBOSE;
++ return;
++}
++
++void set_log_debug_ap(struct autofs_point *ap)
++{
++ ap->logopt = LOGOPT_DEBUG;
++ return;
+ }
+
+-static void syslog_info(unsigned int logopt, const char *msg, ...)
++void log_info(unsigned int logopt, const char *msg, ...)
+ {
+ unsigned int opt_log = logopt & (LOGOPT_DEBUG | LOGOPT_VERBOSE);
+ va_list ap;
+@@ -73,11 +80,18 @@ static void syslog_info(unsigned int logopt, const char *msg, ...)
+ return;
+
+ va_start(ap, msg);
+- vsyslog(LOG_INFO, msg, ap);
++ if (logging_to_syslog)
++ vsyslog(LOG_INFO, msg, ap);
++ else {
++ vfprintf(stderr, msg, ap);
++ fputc('\n', stderr);
++ }
+ va_end(ap);
++
++ return;
+ }
+
+-static void syslog_notice(unsigned int logopt, const char *msg, ...)
++void log_notice(unsigned int logopt, const char *msg, ...)
+ {
+ unsigned int opt_log = logopt & (LOGOPT_DEBUG | LOGOPT_VERBOSE);
+ va_list ap;
+@@ -86,11 +100,18 @@ static void syslog_notice(unsigned int logopt, const char *msg, ...)
+ return;
+
+ va_start(ap, msg);
+- vsyslog(LOG_NOTICE, msg, ap);
++ if (logging_to_syslog)
++ vsyslog(LOG_NOTICE, msg, ap);
++ else {
++ vfprintf(stderr, msg, ap);
++ fputc('\n', stderr);
++ }
+ va_end(ap);
++
++ return;
+ }
+
+-static void syslog_warn(unsigned int logopt, const char *msg, ...)
++void log_warn(unsigned int logopt, const char *msg, ...)
+ {
+ unsigned int opt_log = logopt & (LOGOPT_DEBUG | LOGOPT_VERBOSE);
+ va_list ap;
+@@ -99,70 +120,79 @@ static void syslog_warn(unsigned int logopt, const char *msg, ...)
+ return;
+
+ va_start(ap, msg);
+- vsyslog(LOG_WARNING, msg, ap);
++ if (logging_to_syslog)
++ vsyslog(LOG_WARNING, msg, ap);
++ else {
++ vfprintf(stderr, msg, ap);
++ fputc('\n', stderr);
++ }
+ va_end(ap);
++
++ return;
+ }
+
+-static void syslog_err(unsigned int logopt, const char *msg, ...)
++void log_error(unsigned logopt, const char *msg, ...)
+ {
+ va_list ap;
++
+ va_start(ap, msg);
+- vsyslog(LOG_ERR, msg, ap);
++ if (logging_to_syslog)
++ vsyslog(LOG_ERR, msg, ap);
++ else {
++ vfprintf(stderr, msg, ap);
++ fputc('\n', stderr);
++ }
+ va_end(ap);
++ return;
+ }
+
+-static void syslog_crit(unsigned int logopt, const char *msg, ...)
++void log_crit(unsigned logopt, const char *msg, ...)
+ {
+ va_list ap;
++
+ va_start(ap, msg);
+- vsyslog(LOG_CRIT, msg, ap);
++ if (logging_to_syslog)
++ vsyslog(LOG_CRIT, msg, ap);
++ else {
++ vfprintf(stderr, msg, ap);
++ fputc('\n', stderr);
++ }
+ va_end(ap);
++ return;
+ }
+
+-static void syslog_debug(unsigned int logopt, const char *msg, ...)
++void log_debug(unsigned int logopt, const char *msg, ...)
+ {
++ unsigned int opt_log = logopt & LOGOPT_DEBUG;
+ va_list ap;
+
+- if (!do_debug && !(logopt & LOGOPT_DEBUG))
++ if (!do_debug && !opt_log)
+ return;
+
+ va_start(ap, msg);
+- vsyslog(LOG_DEBUG, msg, ap);
++ if (logging_to_syslog)
++ vsyslog(LOG_WARNING, msg, ap);
++ else {
++ vfprintf(stderr, msg, ap);
++ fputc('\n', stderr);
++ }
+ va_end(ap);
++
++ return;
+ }
+
+-static void to_stderr(unsigned int logopt, const char *msg, ...)
++void logmsg(const char *msg, ...)
+ {
+ va_list ap;
+ va_start(ap, msg);
+- vfprintf(stderr, msg, ap);
+- fputc('\n',stderr);
+- va_end(ap);
+-}
+-
+-void set_mnt_logging(struct autofs_point *ap)
+-{
+- unsigned int opt_verbose = ap->logopt & LOGOPT_VERBOSE;
+- unsigned int opt_debug = ap->logopt & LOGOPT_DEBUG;
+-
+- if (opt_debug) {
+- if (logging_to_syslog)
+- log_debug = syslog_debug;
+- else
+- log_debug = to_stderr;
+- }
+-
+- if (opt_verbose || opt_debug) {
+- if (logging_to_syslog) {
+- log_info = syslog_info;
+- log_notice = syslog_notice;
+- log_warn = syslog_warn;
+- } else {
+- log_info = to_stderr;
+- log_notice = to_stderr;
+- log_warn = to_stderr;
+- }
++ if (logging_to_syslog)
++ vsyslog(LOG_CRIT, msg, ap);
++ else {
++ vfprintf(stderr, msg, ap);
++ fputc('\n', stderr);
+ }
++ va_end(ap);
++ return;
+ }
+
+ void log_to_syslog(void)
+@@ -175,31 +205,13 @@ void log_to_syslog(void)
+ openlog("automount", LOG_PID, LOG_DAEMON);
+ }
+
+- if (do_debug)
+- log_debug = syslog_debug;
+- else
+- log_debug = null;
+-
+- if (do_verbose || do_debug) {
+- log_info = syslog_info;
+- log_notice = syslog_notice;
+- log_warn = syslog_warn;
+- } else {
+- log_info = null;
+- log_notice = null;
+- log_warn = null;
+- }
+-
+- log_error = syslog_err;
+- log_crit = syslog_crit;
+-
+ logging_to_syslog = 1;
+
+ /* Redirect all our file descriptors to /dev/null */
+ nullfd = open("/dev/null", O_RDWR);
+ if (nullfd < 0) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- syslog_crit(LOGOPT_ANY, "cannot open /dev/null: %s", estr);
++ fprintf(stderr, "cannot open /dev/null: %s", estr);
+ exit(1);
+ }
+
+@@ -207,13 +219,15 @@ void log_to_syslog(void)
+ dup2(nullfd, STDOUT_FILENO) < 0 ||
+ dup2(nullfd, STDERR_FILENO) < 0) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- syslog_crit(LOGOPT_ANY,
+- "redirecting file descriptors failed: %s", estr);
++ fprintf(stderr,
++ "redirecting file descriptors failed: %s", estr);
+ exit(1);
+ }
+
+ if (nullfd > 2)
+ close(nullfd);
++
++ return;
+ }
+
+ void log_to_stderr(void)
+@@ -223,23 +237,7 @@ void log_to_stderr(void)
+ closelog();
+ }
+
+- if (do_debug)
+- log_debug = to_stderr;
+- else
+- log_debug = null;
+-
+- if (do_verbose || do_debug) {
+- log_info = to_stderr;
+- log_notice = to_stderr;
+- log_warn = to_stderr;
+- } else {
+- log_info = null;
+- log_notice = null;
+- log_warn = null;
+- }
+-
+- log_error = to_stderr;
+- log_crit = to_stderr;
+-
+ logging_to_syslog = 0;
++
++ return;
+ }
+diff --git a/lib/macros.c b/lib/macros.c
+index 936ae06..fa6db8e 100644
+--- a/lib/macros.c
++++ b/lib/macros.c
+@@ -50,8 +50,7 @@ void dump_table(struct substvar *table)
+ fatal(status);
+
+ while (lv) {
+- debug(LOGOPT_NONE,
+- "lv->def %s lv->val %s lv->next %p",
++ logmsg("lv->def %s lv->val %s lv->next %p",
+ lv->def, lv->val, lv->next);
+ lv = lv->next;
+ }
+diff --git a/lib/master.c b/lib/master.c
+index abc3bc2..2e24ad0 100644
+--- a/lib/master.c
++++ b/lib/master.c
+@@ -524,8 +524,7 @@ void master_source_writelock(struct master_mapent *entry)
+
+ status = pthread_rwlock_wrlock(&entry->source_lock);
+ if (status) {
+- error(LOGOPT_ANY,
+- "master_mapent source write lock failed");
++ logmsg("master_mapent source write lock failed");
+ fatal(status);
+ }
+ return;
+@@ -537,8 +536,7 @@ void master_source_readlock(struct master_mapent *entry)
+
+ status = pthread_rwlock_rdlock(&entry->source_lock);
+ if (status) {
+- error(LOGOPT_ANY,
+- "master_mapent source read lock failed");
++ logmsg("master_mapent source read lock failed");
+ fatal(status);
+ }
+ return;
+@@ -550,8 +548,7 @@ void master_source_unlock(struct master_mapent *entry)
+
+ status = pthread_rwlock_unlock(&entry->source_lock);
+ if (status) {
+- error(LOGOPT_ANY,
+- "master_mapent source unlock failed");
++ logmsg("master_mapent source unlock failed");
+ fatal(status);
+ }
+ return;
+@@ -572,7 +569,7 @@ void master_source_current_wait(struct master_mapent *entry)
+
+ status = pthread_mutex_lock(&entry->current_mutex);
+ if (status) {
+- error(LOGOPT_ANY, "entry current source lock failed");
++ logmsg("entry current source lock failed");
+ fatal(status);
+ }
+
+@@ -580,8 +577,7 @@ void master_source_current_wait(struct master_mapent *entry)
+ status = pthread_cond_wait(
+ &entry->current_cond, &entry->current_mutex);
+ if (status) {
+- error(LOGOPT_ANY,
+- "entry current source condition wait failed");
++ logmsg("entry current source condition wait failed");
+ fatal(status);
+ }
+ }
+@@ -595,14 +591,13 @@ void master_source_current_signal(struct master_mapent *entry)
+
+ status = pthread_cond_signal(&entry->current_cond);
+ if (status) {
+- error(LOGOPT_ANY,
+- "entry current source condition signal failed");
++ logmsg("entry current source condition signal failed");
+ fatal(status);
+ }
+
+ status = pthread_mutex_unlock(&entry->current_mutex);
+ if (status) {
+- error(LOGOPT_ANY, "entry current source unlock failed");
++ logmsg("entry current source unlock failed");
+ fatal(status);
+ }
+
+@@ -770,6 +765,7 @@ struct master *master_new(const char *name, unsigned int timeout, unsigned int g
+ master->default_ghost = ghost;
+ master->default_timeout = timeout;
+ master->default_logging = defaults_get_logging();
++ master->logopt = master->default_logging;
+
+ INIT_LIST_HEAD(&master->mounts);
+
+@@ -778,11 +774,12 @@ struct master *master_new(const char *name, unsigned int timeout, unsigned int g
+
+ int master_read_master(struct master *master, time_t age, int readall)
+ {
++ unsigned int logopt = master->logopt;
+ struct mapent_cache *nc;
+
+ nc = cache_init_null_cache(master);
+ if (!nc) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "failed to init null map cache for %s", master->name);
+ return 0;
+ }
+@@ -791,7 +788,7 @@ int master_read_master(struct master *master, time_t age, int readall)
+ master_init_scan();
+
+ if (!lookup_nss_read_master(master, age)) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "can't read master map %s", master->name);
+ return 0;
+ }
+@@ -802,7 +799,7 @@ int master_read_master(struct master *master, time_t age, int readall)
+
+ if (list_empty(&master->mounts)) {
+ master_mutex_unlock();
+- warn(LOGOPT_ANY, "no mounts in table");
++ warn(logopt, "no mounts in table");
+ return 1;
+ }
+
+@@ -934,6 +931,7 @@ void master_notify_state_change(struct master *master, int sig)
+ struct autofs_point *ap;
+ struct list_head *p;
+ int state_pipe, cur_state;
++ unsigned int logopt;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ master_mutex_lock();
+@@ -944,6 +942,7 @@ void master_notify_state_change(struct master *master, int sig)
+ entry = list_entry(p, struct master_mapent, list);
+
+ ap = entry->ap;
++ logopt = ap->logopt;
+
+ state_mutex_lock(ap);
+
+@@ -978,7 +977,7 @@ void master_notify_state_change(struct master *master, int sig)
+ }
+ next:
+ if (next != ST_INVAL)
+- debug(ap->logopt,
++ debug(logopt,
+ "sig %d switching %s from %d to %d",
+ sig, ap->path, ap->state, next);
+
+@@ -1230,6 +1229,11 @@ int master_list_empty(struct master *master)
+ return res;
+ }
+
++inline unsigned int master_get_logopt(void)
++{
++ return master_list ? master_list->logopt : LOGOPT_NONE;
++}
++
+ int master_kill(struct master *master)
+ {
+ if (!list_empty(&master->mounts))
+@@ -1251,6 +1255,6 @@ void dump_master(struct master *master)
+ head = &master->mounts;
+ list_for_each(p, head) {
+ struct master_mapent *this = list_entry(p, struct master_mapent, list);
+- debug(LOGOPT_ANY, "path %s", this->path);
++ logmsg("path %s", this->path);
+ }
+ }
+diff --git a/lib/master_parse.y b/lib/master_parse.y
+index 70b48be..a767f9e 100644
+--- a/lib/master_parse.y
++++ b/lib/master_parse.y
+@@ -585,13 +585,13 @@ static char *master_strdup(char *str)
+
+ static int master_error(const char *s)
+ {
+- error(LOGOPT_ANY, "%s while parsing map.", s);
++ logmsg("%s while parsing map.", s);
+ return 0;
+ }
+
+ static int master_notify(const char *s)
+ {
+- warn(LOGOPT_ANY, "syntax error in map near [ %s ]", s);
++ logmsg("syntax error in map near [ %s ]", s);
+ return(0);
+ }
+
+@@ -704,6 +704,7 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ struct master_mapent *entry, *new;
+ struct map_source *source;
+ unsigned int logopt = logging;
++ unsigned int m_logopt = master->logopt;
+ int ret;
+
+ local_init_vars();
+@@ -758,8 +759,8 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ } else {
+ if (entry->age && entry->age == age) {
+ if (strcmp(path, "/-")) {
+- warn(LOGOPT_VERBOSE,
+- "ignoring duplicate indirect mount %s",
++ info(m_logopt,
++ "ignoring duplicate indirect mount %s",
+ path);
+ local_free_vars();
+ return 0;
+@@ -770,13 +771,12 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ if (!entry->ap) {
+ ret = master_add_autofs_point(entry, timeout, logopt, ghost, 0);
+ if (!ret) {
+- error(LOGOPT_ANY, "failed to add autofs_point");
++ error(m_logopt, "failed to add autofs_point");
+ if (new)
+ master_free_mapent(new);
+ local_free_vars();
+ return 0;
+ }
+- set_mnt_logging(entry->ap);
+ } else {
+ struct autofs_point *ap = entry->ap;
+ time_t tout = timeout;
+@@ -786,14 +786,11 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ * use the ghost, log and timeout of the first
+ */
+ if (entry->age < age) {
+- ap->ghost = ghost;
+- ap->logopt = logopt;
+ ap->exp_timeout = timeout;
+ ap->exp_runfreq = (ap->exp_timeout + CHECK_RATIO - 1) / CHECK_RATIO;
+ if (ap->ioctlfd != -1 && ap->type == LKP_INDIRECT)
+ ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout);
+ }
+- set_mnt_logging(ap);
+ }
+ entry->ap->random_selection = random_selection;
+
+@@ -809,7 +806,7 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ source = master_add_map_source(entry, type, format, age,
+ local_argc, (const char **) local_argv);
+ if (!source) {
+- error(LOGOPT_ANY, "failed to add source");
++ error(m_logopt, "failed to add source");
+ if (new)
+ master_free_mapent(new);
+ local_free_vars();
+@@ -817,9 +814,9 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ }
+
+ if (!source->mc) {
+- source->mc = cache_init(source);
++ source->mc = cache_init(entry->ap, source);
+ if (!source->mc) {
+- error(LOGOPT_ANY, "failed to init source cache");
++ error(m_logopt, "failed to init source cache");
+ if (new)
+ master_free_mapent(new);
+ local_free_vars();
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 2735223..00cd223 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -368,7 +368,7 @@ int master_wrap(void)
+
+ static void master_echo(void)
+ {
+- debug(LOGOPT_NONE, "%s", master_text);
++ logmsg("%s", master_text);
+ return;
+ }
+
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 0e428e8..425a65a 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -126,7 +126,7 @@ char *make_options_string(char *path, int pipefd, char *extra)
+
+ options = malloc(MAX_OPTIONS_LEN + 1);
+ if (!options) {
+- crit(LOGOPT_ANY, "can't malloc options string");
++ logerr("can't malloc options string");
+ return NULL;
+ }
+
+@@ -141,13 +141,12 @@ char *make_options_string(char *path, int pipefd, char *extra)
+ AUTOFS_MAX_PROTO_VERSION);
+
+ if (len >= MAX_OPTIONS_LEN) {
+- crit(LOGOPT_ANY, "buffer to small for options - truncated");
++ logerr("buffer to small for options - truncated");
+ len = MAX_OPTIONS_LEN - 1;
+ }
+
+ if (len < 0) {
+- crit(LOGOPT_ANY,
+- "failed to malloc autofs mount options for %s", path);
++ logerr("failed to malloc autofs mount options for %s", path);
+ free(options);
+ return NULL;
+ }
+@@ -163,7 +162,7 @@ char *make_mnt_name_string(char *path)
+
+ mnt_name = malloc(MAX_MNT_NAME_LEN + 1);
+ if (!mnt_name) {
+- crit(LOGOPT_ANY, "can't malloc mnt_name string");
++ logerr("can't malloc mnt_name string");
+ return NULL;
+ }
+
+@@ -171,13 +170,12 @@ char *make_mnt_name_string(char *path)
+ mnt_name_template, (unsigned) getpid());
+
+ if (len >= MAX_MNT_NAME_LEN) {
+- crit(LOGOPT_ANY, "buffer to small for mnt_name - truncated");
++ logerr("buffer to small for mnt_name - truncated");
+ len = MAX_MNT_NAME_LEN - 1;
+ }
+
+ if (len < 0) {
+- crit(LOGOPT_ANY,
+- "failed setting up mnt_name for autofs path %s", path);
++ logerr("failed setting up mnt_name for autofs path %s", path);
+ free(mnt_name);
+ return NULL;
+ }
+@@ -207,7 +205,7 @@ struct mnt_list *get_mnt_list(const char *table, const char *path, int include)
+ tab = setmntent(table, "r");
+ if (!tab) {
+ char *estr = strerror_r(errno, buf, PATH_MAX - 1);
+- error(LOGOPT_ANY, "setmntent: %s", estr);
++ logerr("setmntent: %s", estr);
+ return NULL;
+ }
+
+@@ -398,7 +396,7 @@ int is_mounted(const char *table, const char *path, unsigned int type)
+ tab = setmntent(table, "r");
+ if (!tab) {
+ char *estr = strerror_r(errno, buf, PATH_MAX - 1);
+- error(LOGOPT_ANY, "setmntent: %s", estr);
++ logerr("setmntent: %s", estr);
+ return 0;
+ }
+
+@@ -443,7 +441,7 @@ int has_fstab_option(const char *opt)
+ tab = setmntent(_PATH_MNTTAB, "r");
+ if (!tab) {
+ char *estr = strerror_r(errno, buf, PATH_MAX - 1);
+- error(LOGOPT_ANY, "setmntent: %s", estr);
++ logerr("setmntent: %s", estr);
+ return 0;
+ }
+
+@@ -471,7 +469,7 @@ char *find_mnt_ino(const char *table, dev_t dev, ino_t ino)
+ tab = setmntent(table, "r");
+ if (!tab) {
+ char *estr = strerror_r(errno, buf, (size_t) PATH_MAX - 1);
+- error(LOGOPT_ANY, "setmntent: %s", estr);
++ logerr("setmntent: %s", estr);
+ return 0;
+ }
+
+@@ -667,7 +665,7 @@ struct mnt_list *tree_make_mnt_tree(const char *table, const char *path)
+ tab = setmntent(table, "r");
+ if (!tab) {
+ char *estr = strerror_r(errno, buf, PATH_MAX - 1);
+- error(LOGOPT_ANY, "setmntent: %s", estr);
++ logerr("setmntent: %s", estr);
+ return NULL;
+ }
+
+diff --git a/lib/nss_parse.y b/lib/nss_parse.y
+index e559696..90b7d25 100644
+--- a/lib/nss_parse.y
++++ b/lib/nss_parse.y
+@@ -127,13 +127,13 @@ status_exp: STATUS EQUAL ACTION
+
+ static int nss_ignore(const char *s)
+ {
+- msg("ignored invalid nsswitch config near [ %s ]", s);
++ logmsg("ignored invalid nsswitch config near [ %s ]", s);
+ return(0);
+ }
+
+ static int nss_error(const char *s)
+ {
+- msg("syntax error in nsswitch config near [ %s ]\n", s);
++ logmsg("syntax error in nsswitch config near [ %s ]\n", s);
+ return(0);
+ }
+
+@@ -167,7 +167,7 @@ int nsswitch_parse(struct list_head *list)
+
+ nsswitch = fopen(NSSWITCH_FILE, "r");
+ if (!nsswitch) {
+- error(LOGOPT_ANY, "couldn't open %s\n", NSSWITCH_FILE);
++ logerr("couldn't open %s\n", NSSWITCH_FILE);
+ return 1;
+ }
+
+diff --git a/lib/nss_tok.l b/lib/nss_tok.l
+index f96b47f..c435b63 100644
+--- a/lib/nss_tok.l
++++ b/lib/nss_tok.l
+@@ -135,6 +135,6 @@ int nss_wrap(void)
+
+ static void nss_echo(void)
+ {
+- msg("%s", nss_text);
++ logmsg("%s", nss_text);
+ return;
+ }
+diff --git a/lib/parse_subs.c b/lib/parse_subs.c
+index 3627f44..5422fef 100644
+--- a/lib/parse_subs.c
++++ b/lib/parse_subs.c
+@@ -337,9 +337,9 @@ int umount_ent(struct autofs_point *ap, const char *path)
+ * and EBADSLT relates to CD changer not responding.
+ */
+ if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) {
+- rv = spawn_umount(log_debug, path, NULL);
++ rv = spawn_umount(ap->logopt, path, NULL);
+ } else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) {
+- rv = spawn_umount(log_debug, path, NULL);
++ rv = spawn_umount(ap->logopt, path, NULL);
+ }
+
+ /* We are doing a forced shutcwdown down so unlink busy mounts */
+@@ -356,8 +356,8 @@ int umount_ent(struct autofs_point *ap, const char *path)
+ }
+
+ if (ap->state == ST_SHUTDOWN_FORCE) {
+- msg("forcing umount of %s", path);
+- rv = spawn_umount(log_debug, "-l", path, NULL);
++ info(ap->logopt, "forcing umount of %s", path);
++ rv = spawn_umount(ap->logopt, "-l", path, NULL);
+ }
+
+ /*
+@@ -503,7 +503,7 @@ int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me
+ * the offset triggers back.
+ */
+ if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) {
+- msg("unmounting dir = %s", root);
++ info(ap->logopt, "unmounting dir = %s", root);
+ if (umount_ent(ap, root)) {
+ if (!mount_multi_triggers(ap, root, me, "/"))
+ warn(ap->logopt,
+diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
+index d79a94f..5797639 100644
+--- a/lib/rpc_subs.c
++++ b/lib/rpc_subs.c
+@@ -96,7 +96,7 @@ static CLIENT *create_udp_client(struct conn_info *info)
+ if (ret || !result) {
+ int err = ghn_errno == -1 ? errno : ghn_errno;
+ char *estr = strerror_r(err, buf, HOST_ENT_BUF_SIZE);
+- error(LOGOPT_ANY, "hostname lookup failed: %s", estr);
++ logerr("hostname lookup failed: %s", estr);
+ goto out_close;
+ }
+ memcpy(&raddr.sin_addr.s_addr, php->h_addr, php->h_length);
+@@ -305,7 +305,7 @@ static CLIENT *create_tcp_client(struct conn_info *info)
+ if (ret || !result) {
+ int err = ghn_errno == -1 ? errno : ghn_errno;
+ char *estr = strerror_r(err, buf, HOST_ENT_BUF_SIZE);
+- error(LOGOPT_ANY, "hostname lookup failed: %s", estr);
++ logerr("hostname lookup failed: %s", estr);
+ goto out_close;
+ }
+ memcpy(&addr.sin_addr.s_addr, php->h_addr, php->h_length);
+diff --git a/man/automount.8 b/man/automount.8
+index e203a3e..5cd63c7 100644
+--- a/man/automount.8
++++ b/man/automount.8
+@@ -62,6 +62,22 @@ setting.
+ .TP
+ .I "\-V, \-\-version"
+ Display the version number, then exit.
++.TP
++.I "\-l, \-\-set-log-priority priority path [path,...]"
++Set the daemon log priority to the specified value. Valid values include
++the numbers 0-7, or the strings emerg, alert, crit, err, warning, notice,
++info, or debug. Log level debug will log everything, log levels info, warn
++(or warning), or notice with enable the daemon verbose logging. Any other
++level will set basic logging. Note that enabling debug or verbose
++logging in the autofs global configuration will override dynamic log level
++changes. For example, if verbose logging is set in the configuration then
++attempting to set logging to basic logging, by using alert, crit, err
++or emerg won't stop the verbose logging. However, setting logging to debug
++will lead to everything (debug logging) being logged witch can then also
++be disabled, returning the daemon to verbose logging.
++.P
++The \fIpath\fP argument corresponds to the automounted
++path name as specified in the master map.
+ .SH ARGUMENTS
+ \fBautomount\fP takes one optional argument, the name of the master map to
+ use.
+diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
+index 68e5dd7..18733f3 100644
+--- a/modules/cyrus-sasl.c
++++ b/modules/cyrus-sasl.c
+@@ -96,18 +96,18 @@ sasl_log_func(void *context, int level, const char *message)
+ switch (level) {
+ case SASL_LOG_ERR:
+ case SASL_LOG_FAIL:
+- error(LOGOPT_ANY, "%s", message);
++ logerr("%s", message);
+ break;
+ case SASL_LOG_WARN:
+- warn(LOGOPT_ANY, "%s", message);
++ logmsg("%s", message);
+ break;
+ case SASL_LOG_NOTE:
+- info(LOGOPT_ANY, "%s", message);
++ logmsg("%s", message);
+ break;
+ case SASL_LOG_DEBUG:
+ case SASL_LOG_TRACE:
+ case SASL_LOG_PASS:
+- debug(LOGOPT_NONE, "%s", message);
++ debug(LOGOPT_DEBUG, "%s", message);
+ break;
+ default:
+ break;
+@@ -129,7 +129,7 @@ getuser_func(void *context, int id, const char **result, unsigned *len)
+ *len = strlen(sasl_auth_id);
+ break;
+ default:
+- error(LOGOPT_ANY, "unknown id in request: %d", id);
++ error(LOGOPT_VERBOSE, "unknown id in request: %d", id);
+ return SASL_FAIL;
+ }
+
+@@ -166,7 +166,7 @@ getpass_func(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
+ * the returned data.
+ */
+ char **
+-get_server_SASL_mechanisms(LDAP *ld)
++get_server_SASL_mechanisms(unsigned logopt, LDAP *ld)
+ {
+ int ret;
+ const char *saslattrlist[] = {"supportedSASLmechanisms", NULL};
+@@ -178,7 +178,7 @@ get_server_SASL_mechanisms(LDAP *ld)
+ NULL, NULL,
+ NULL, LDAP_NO_LIMIT, &results);
+ if (ret != LDAP_SUCCESS) {
+- error(LOGOPT_ANY, "%s", ldap_err2string(ret));
++ error(logopt, "%s", ldap_err2string(ret));
+ return NULL;
+ }
+
+@@ -186,7 +186,7 @@ get_server_SASL_mechanisms(LDAP *ld)
+ if (entry == NULL) {
+ /* No root DSE. (!) */
+ ldap_msgfree(results);
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ "a lookup of \"supportedSASLmechanisms\" returned "
+ "no results.");
+ return NULL;
+@@ -196,7 +196,7 @@ get_server_SASL_mechanisms(LDAP *ld)
+ ldap_msgfree(results);
+ if (mechanisms == NULL) {
+ /* Well, that was a waste of time. */
+- msg("No SASL authentication mechanisms are supported"
++ info(logopt, "No SASL authentication mechanisms are supported"
+ " by the LDAP server.");
+ return NULL;
+ }
+@@ -208,7 +208,7 @@ get_server_SASL_mechanisms(LDAP *ld)
+ * Returns 0 upon successful connect, -1 on failure.
+ */
+ int
+-do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
++do_sasl_bind(unsigned logopt, LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ unsigned int *clientoutlen, const char *auth_mech, int sasl_result)
+ {
+ int ret, msgid, bind_result;
+@@ -226,7 +226,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ &client_cred : NULL,
+ NULL, NULL, &msgid);
+ if (ret != LDAP_SUCCESS) {
+- crit(LOGOPT_ANY,
++ crit(logopt,
+ "Error sending sasl_bind request to "
+ "the server: %s", ldap_err2string(ret));
+ return -1;
+@@ -236,7 +236,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ results = NULL;
+ ret = ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &results);
+ if (ret != LDAP_RES_BIND) {
+- crit(LOGOPT_ANY,
++ crit(logopt,
+ "Error while waiting for response to "
+ "sasl_bind request: %s", ldap_err2string(ret));
+ return -1;
+@@ -264,7 +264,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ ret = ldap_get_option(ld, LDAP_OPT_RESULT_CODE,
+ &bind_result);
+ if (ret != LDAP_SUCCESS) {
+- crit(LOGOPT_ANY,
++ crit(logopt,
+ "Error retrieving response to sasl_bind "
+ "request: %s", ldap_err2string(ret));
+ ret = -1;
+@@ -277,7 +277,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ bind_result = ret;
+ break;
+ default:
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ "Error parsing response to sasl_bind "
+ "request: %s.", ldap_err2string(ret));
+ break;
+@@ -299,7 +299,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ expected_data = sasl_result == SASL_CONTINUE;
+
+ if (have_data && !expected_data) {
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ "The LDAP server sent data in response to our "
+ "bind request, but indicated that the bind was "
+ "complete. LDAP SASL bind with mechansim %s "
+@@ -308,7 +308,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ break;
+ }
+ if (expected_data && !have_data) {
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ "The LDAP server indicated that the LDAP SASL "
+ "bind was incomplete, but did not provide the "
+ "required data to proceed. LDAP SASL bind with "
+@@ -340,7 +340,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ */
+ if ((*clientoutlen > 0) &&
+ (bind_result != LDAP_SASL_BIND_IN_PROGRESS)) {
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ "We have data for the server, "
+ "but it thinks we are done!");
+ /* XXX should print out debug data here */
+@@ -372,7 +372,7 @@ do_sasl_bind(LDAP *ld, sasl_conn_t *conn, const char **clientout,
+ * Upon failure, -1 is returned.
+ */
+ int
+-sasl_do_kinit(struct lookup_context *ctxt)
++sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ {
+ krb5_error_code ret;
+ krb5_principal tgs_princ, krb5_client_princ = ctxt->krb5_client_princ;
+@@ -384,33 +384,33 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ return 0;
+ ctxt->kinit_done = 1;
+
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ "initializing kerberos ticket: client principal %s ",
+ ctxt->client_princ ? "" : "autofsclient");
+
+ ret = krb5_init_context(&ctxt->krb5ctxt);
+ if (ret) {
+- error(LOGOPT_ANY, "krb5_init_context failed with %d", ret);
++ error(logopt, "krb5_init_context failed with %d", ret);
+ return -1;
+ }
+
+ ret = krb5_cc_resolve(ctxt->krb5ctxt, krb5ccval, &ctxt->krb5_ccache);
+ if (ret) {
+- error(LOGOPT_ANY, "krb5_cc_resolve failed with error %d",
++ error(logopt, "krb5_cc_resolve failed with error %d",
+ ret);
+ krb5_free_context(ctxt->krb5ctxt);
+ return -1;
+ }
+
+ if (ctxt->client_princ) {
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ "calling krb5_parse_name on client principal %s",
+ ctxt->client_princ);
+
+ ret = krb5_parse_name(ctxt->krb5ctxt, ctxt->client_princ,
+ &krb5_client_princ);
+ if (ret) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "krb5_parse_name failed for "
+ "specified client principal %s",
+ ctxt->client_princ);
+@@ -419,14 +419,14 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ } else {
+ char *tmp_name = NULL;
+
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ "calling krb5_sname_to_principal using defaults");
+
+ ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
+ "autofsclient", KRB5_NT_SRV_HST,
+ &krb5_client_princ);
+ if (ret) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "krb5_sname_to_principal failed for "
+ "%s with error %d",
+ ctxt->client_princ ? "" : "autofsclient", ret);
+@@ -437,13 +437,13 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ ret = krb5_unparse_name(ctxt->krb5ctxt,
+ krb5_client_princ, &tmp_name);
+ if (ret) {
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ "krb5_unparse_name failed with error %d",
+ ret);
+ goto out_cleanup_cc;
+ }
+
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ "principal used for authentication: \"%s\"", tmp_name);
+
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name);
+@@ -458,19 +458,19 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ krb5_princ_realm(ctxt->krb5ctxt, krb5_client_princ)->data,
+ 0);
+ if (ret) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "krb5_build_principal failed with error %d", ret);
+ goto out_cleanup_cc;
+ }
+
+ ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name);
+ if (ret) {
+- error(LOGOPT_ANY, "krb5_unparse_name failed with error %d",
++ error(logopt, "krb5_unparse_name failed with error %d",
+ ret);
+ goto out_cleanup_cc;
+ }
+
+- debug(LOGOPT_NONE, "Using tgs name %s", tgs_name);
++ debug(logopt, "Using tgs name %s", tgs_name);
+
+ memset(&my_creds, 0, sizeof(my_creds));
+ ret = krb5_get_init_creds_keytab(ctxt->krb5ctxt, &my_creds,
+@@ -479,7 +479,7 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ 0 /* relative start time */,
+ tgs_name, NULL);
+ if (ret) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "krb5_get_init_creds_keytab failed with error %d",
+ ret);
+ goto out_cleanup_unparse;
+@@ -500,7 +500,7 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ fatal(status);
+
+ if (ret) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "krb5_cc_initialize failed with error %d", ret);
+ goto out_cleanup_unparse;
+ }
+@@ -508,7 +508,7 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ /* and store credentials for that principal */
+ ret = krb5_cc_store_cred(ctxt->krb5ctxt, ctxt->krb5_ccache, &my_creds);
+ if (ret) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ "krb5_cc_store_cred failed with error %d", ret);
+ goto out_cleanup_unparse;
+ }
+@@ -516,12 +516,12 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ /* finally, set the environment variable to point to our
+ * credentials cache */
+ if (setenv(krb5ccenv, krb5ccval, 1) != 0) {
+- error(LOGOPT_ANY, "setenv failed with %d", errno);
++ error(logopt, "setenv failed with %d", errno);
+ goto out_cleanup_unparse;
+ }
+ ctxt->kinit_successful = 1;
+
+- debug(LOGOPT_NONE, "Kerberos authentication was successful!");
++ debug(logopt, "Kerberos authentication was successful!");
+
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
+
+@@ -540,7 +540,7 @@ out_cleanup_cc:
+ else
+ ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ if (ret)
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ "krb5_cc_destroy failed with non-fatal error %d", ret);
+
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+@@ -559,7 +559,7 @@ out_cleanup_cc:
+ * Returns a valid sasl_conn_t pointer upon success, NULL on failure.
+ */
+ sasl_conn_t *
+-sasl_bind_mech(LDAP *ldap, struct lookup_context *ctxt, const char *mech)
++sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *mech)
+ {
+ sasl_conn_t *conn;
+ char *tmp, *host = NULL;
+@@ -569,15 +569,15 @@ sasl_bind_mech(LDAP *ldap, struct lookup_context *ctxt, const char *mech)
+ int result;
+
+ if (!strncmp(mech, "GSSAPI", 6)) {
+- if (sasl_do_kinit(ctxt) != 0)
++ if (sasl_do_kinit(logopt, ctxt) != 0)
+ return NULL;
+ }
+
+- debug(LOGOPT_NONE, "Attempting sasl bind with mechanism %s", mech);
++ debug(logopt, "Attempting sasl bind with mechanism %s", mech);
+
+ result = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
+ if (result != LDAP_SUCCESS || !host) {
+- debug(LOGOPT_NONE, "failed to get hostname for connection");
++ debug(logopt, "failed to get hostname for connection");
+ return NULL;
+ }
+
+@@ -587,7 +587,7 @@ sasl_bind_mech(LDAP *ldap, struct lookup_context *ctxt, const char *mech)
+ /* Create a new authentication context for the service. */
+ result = sasl_client_new("ldap", host, NULL, NULL, NULL, 0, &conn);
+ if (result != SASL_OK) {
+- error(LOGOPT_ANY, "sasl_client_new failed with error %d",
++ error(logopt, "sasl_client_new failed with error %d",
+ result);
+ ldap_memfree(host);
+ return NULL;
+@@ -599,23 +599,23 @@ sasl_bind_mech(LDAP *ldap, struct lookup_context *ctxt, const char *mech)
+
+ /* OK and CONTINUE are the only non-fatal return codes here. */
+ if ((result != SASL_OK) && (result != SASL_CONTINUE)) {
+- error(LOGOPT_ANY, "sasl_client start failed with error: %s",
++ error(logopt, "sasl_client start failed with error: %s",
+ sasl_errdetail(conn));
+ ldap_memfree(host);
+ sasl_dispose(&conn);
+ return NULL;
+ }
+
+- result = do_sasl_bind(ldap, conn,
++ result = do_sasl_bind(logopt, ldap, conn,
+ &clientout, &clientoutlen, chosen_mech, result);
+ if (result == 0) {
+ ldap_memfree(host);
+- debug(LOGOPT_NONE, "sasl bind with mechanism %s succeeded",
++ debug(logopt, "sasl bind with mechanism %s succeeded",
+ chosen_mech);
+ return conn;
+ }
+
+- info(LOGOPT_ANY, "sasl bind with mechanism %s failed", mech);
++ info(logopt, "sasl bind with mechanism %s failed", mech);
+
+ /* sasl bind failed */
+ ldap_memfree(host);
+@@ -629,14 +629,14 @@ sasl_bind_mech(LDAP *ldap, struct lookup_context *ctxt, const char *mech)
+ * -1 on error or if no mechanism is supported by both client and server.
+ */
+ sasl_conn_t *
+-sasl_choose_mech(LDAP *ldap, struct lookup_context *ctxt)
++sasl_choose_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ {
+ sasl_conn_t *conn;
+ int authenticated;
+ int i;
+ char **mechanisms;
+
+- mechanisms = get_server_SASL_mechanisms(ldap);
++ mechanisms = get_server_SASL_mechanisms(logopt, ldap);
+ if (!mechanisms)
+ return NULL;
+
+@@ -652,12 +652,11 @@ sasl_choose_mech(LDAP *ldap, struct lookup_context *ctxt)
+ if (authtype_requires_creds(mechanisms[i]))
+ continue;
+
+- conn = sasl_bind_mech(ldap, ctxt, mechanisms[i]);
++ conn = sasl_bind_mech(logopt, ldap, ctxt, mechanisms[i]);
+ if (conn) {
+ ctxt->sasl_mech = strdup(mechanisms[i]);
+ if (!ctxt->sasl_mech) {
+- crit(LOGOPT_ANY,
+- "Successfully authenticated with "
++ crit(logopt, "Successfully authenticated with "
+ "mechanism %s, but failed to allocate "
+ "memory to hold the mechanism type.",
+ mechanisms[i]);
+@@ -668,11 +667,11 @@ sasl_choose_mech(LDAP *ldap, struct lookup_context *ctxt)
+ authenticated = 1;
+ break;
+ }
+- debug(LOGOPT_NONE, "Failed to authenticate with mech %s",
++ debug(logopt, "Failed to authenticate with mech %s",
+ mechanisms[i]);
+ }
+
+- debug(LOGOPT_NONE, "authenticated: %d, sasl_mech: %s",
++ debug(logopt, "authenticated: %d, sasl_mech: %s",
+ authenticated, ctxt->sasl_mech);
+
+ ldap_value_free(mechanisms);
+@@ -680,14 +679,14 @@ sasl_choose_mech(LDAP *ldap, struct lookup_context *ctxt)
+ }
+
+ int
+-autofs_sasl_bind(LDAP *ldap, struct lookup_context *ctxt)
++autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ {
+ sasl_conn_t *conn;
+
+ if (!ctxt->sasl_mech)
+ return -1;
+
+- conn = sasl_bind_mech(ldap, ctxt, ctxt->sasl_mech);
++ conn = sasl_bind_mech(logopt, ldap, ctxt, ctxt->sasl_mech);
+ if (!conn)
+ return -1;
+
+@@ -717,13 +716,13 @@ autofs_sasl_unbind(struct lookup_context *ctxt)
+ * -1 - Failure
+ */
+ int
+-autofs_sasl_init(LDAP *ldap, struct lookup_context *ctxt)
++autofs_sasl_init(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ {
+ sasl_conn_t *conn;
+
+ /* Start up Cyrus SASL--only needs to be done once. */
+ if (sasl_client_init(callbacks) != SASL_OK) {
+- error(LOGOPT_ANY, "sasl_client_init failed");
++ error(logopt, "sasl_client_init failed");
+ return -1;
+ }
+
+@@ -736,9 +735,9 @@ autofs_sasl_init(LDAP *ldap, struct lookup_context *ctxt)
+ * select one.
+ */
+ if (ctxt->sasl_mech)
+- conn = sasl_bind_mech(ldap, ctxt, ctxt->sasl_mech);
++ conn = sasl_bind_mech(logopt, ldap, ctxt, ctxt->sasl_mech);
+ else
+- conn = sasl_choose_mech(ldap, ctxt);
++ conn = sasl_choose_mech(logopt, ldap, ctxt);
+
+ if (conn) {
+ sasl_dispose(&conn);
+@@ -772,8 +771,7 @@ autofs_sasl_done(struct lookup_context *ctxt)
+ else
+ ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ if (ret)
+- warn(LOGOPT_ANY,
+- "krb5_cc_destroy failed with non-fatal error %d",
++ logmsg("krb5_cc_destroy failed with non-fatal error %d",
+ ret);
+
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+@@ -782,8 +780,7 @@ autofs_sasl_done(struct lookup_context *ctxt)
+
+ krb5_free_context(ctxt->krb5ctxt);
+ if (unsetenv(krb5ccenv) != 0)
+- warn(LOGOPT_ANY,
+- "unsetenv failed with error %d", errno);
++ logerr("unsetenv failed with error %d", errno);
+
+ ctxt->krb5ctxt = NULL;
+ ctxt->krb5_ccache = NULL;
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index 31ee0fb..921b32b 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -63,13 +63,13 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt = malloc(sizeof(struct lookup_context));
+ if (!ctxt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return 1;
+ }
+
+ if (argc < 1) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "No map name");
++ logerr(MODPREFIX "No map name");
+ return 1;
+ }
+
+@@ -77,21 +77,21 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+
+ if (ctxt->mapname[0] != '/') {
+ free(ctxt);
+- msg(MODPREFIX "file map %s is not an absolute pathname",
+- argv[0]);
++ logmsg(MODPREFIX
++ "file map %s is not an absolute pathname", argv[0]);
+ return 1;
+ }
+
+ if (access(ctxt->mapname, R_OK)) {
+ free(ctxt);
+- msg(MODPREFIX "file map %s missing or not readable",
+- argv[0]);
++ warn(LOGOPT_NONE, MODPREFIX
++ "file map %s missing or not readable", argv[0]);
+ return 1;
+ }
+
+ if (stat(ctxt->mapname, &st)) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "file map %s, could not stat",
++ logmsg(MODPREFIX "file map %s, could not stat",
+ argv[0]);
+ return 1;
+ }
+@@ -104,7 +104,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parse) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
++ logmsg(MODPREFIX "failed to open parse context");
+ return 1;
+ }
+ *context = ctxt;
+@@ -112,7 +112,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ return 0;
+ }
+
+-static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsigned int *m_len)
++static int read_one(unsigned logopt, FILE *f, char *key, unsigned int *k_len, char *mapent, unsigned int *m_len)
+ {
+ char *kptr, *p;
+ int mapent_len, key_len;
+@@ -193,7 +193,7 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig
+ if (gotten == got_plus)
+ goto got_it;
+ else if (escape == esc_all) {
+- warn(LOGOPT_ANY, MODPREFIX
++ warn(logopt, MODPREFIX
+ "unmatched \" in map key %s", key);
+ goto next;
+ } else if (escape != esc_val)
+@@ -208,7 +208,7 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig
+ if (key_len == KEY_MAX_LEN) {
+ state = st_badent;
+ gotten = got_nothing;
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ MODPREFIX "map key \"%s...\" "
+ "is too long. The maximum key "
+ "length is %d", key,
+@@ -245,7 +245,7 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig
+ state = st_begin;
+ if (gotten == got_real || gotten == getting)
+ goto got_it;
+- warn(LOGOPT_ANY, MODPREFIX
++ warn(logopt, MODPREFIX
+ "bad map entry \"%s...\" for key "
+ "\"%s\"", mapent, key);
+ goto next;
+@@ -286,7 +286,7 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig
+ if (ch == '\n') {
+ if (escape == esc_all) {
+ state = st_begin;
+- warn(LOGOPT_ANY, MODPREFIX
++ warn(logopt, MODPREFIX
+ "unmatched \" in %s for key %s",
+ mapent, key);
+ goto next;
+@@ -310,7 +310,7 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig
+ goto got_it;
+ ungetc(nch, f);
+ } else {
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ MODPREFIX "map entry \"%s...\" for key "
+ "\"%s\" is too long. The maximum entry"
+ " size is %d", mapent, key,
+@@ -388,6 +388,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ unsigned int timeout = master->default_timeout;
+ unsigned int logging = master->default_logging;
++ unsigned int logopt = master->logopt;
+ char *buffer;
+ int blen;
+ char *path;
+@@ -402,29 +403,28 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ return NSS_STATUS_UNAVAIL;
+
+ if (master->depth > MAX_INCLUDE_DEPTH) {
+- error(LOGOPT_ANY,
+- MODPREFIX
++ error(logopt, MODPREFIX
+ "maximum include depth exceeded %s", master->name);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ path = alloca(KEY_MAX_LEN + 1);
+ if (!path) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX "could not malloc storage for path");
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ ent = alloca(MAPENT_MAX_LEN + 1);
+ if (!ent) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX "could not malloc storage for mapent");
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ f = fopen(ctxt->mapname, "r");
+ if (!f) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX "could not open master map file %s",
+ ctxt->mapname);
+ return NSS_STATUS_UNAVAIL;
+@@ -438,19 +438,19 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ }
+
+ while(1) {
+- entry = read_one(f, path, &path_len, ent, &ent_len);
++ entry = read_one(logopt, f, path, &path_len, ent, &ent_len);
+ if (!entry) {
+ if (feof(f))
+ break;
+ if (ferror(f)) {
+- warn(LOGOPT_ANY, MODPREFIX
++ warn(logopt, MODPREFIX
+ "error reading map %s", ctxt->mapname);
+ break;
+ }
+ continue;
+ }
+
+- debug(LOGOPT_NONE, MODPREFIX "read entry %s", path);
++ debug(logopt, MODPREFIX "read entry %s", path);
+
+ /*
+ * If key starts with '+' it has to be an
+@@ -470,7 +470,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ master->depth++;
+ status = lookup_nss_read_master(master, age);
+ if (!status)
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ MODPREFIX
+ "failed to read included master map %s",
+ master->name);
+@@ -482,7 +482,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ blen = path_len + 1 + ent_len + 1;
+ buffer = malloc(blen);
+ if (!buffer) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX "could not malloc parse buffer");
+ return NSS_STATUS_UNAVAIL;
+ }
+@@ -503,7 +503,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ }
+
+ if (fstat(fd, &st)) {
+- crit(LOGOPT_ANY, MODPREFIX "file map %s, could not stat",
++ crit(logopt, MODPREFIX "file map %s, could not stat",
+ ctxt->mapname);
+ return NSS_STATUS_UNAVAIL;
+ }
+@@ -684,12 +684,12 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+ }
+
+ while(1) {
+- entry = read_one(f, key, &k_len, mapent, &m_len);
++ entry = read_one(ap->logopt, f, key, &k_len, mapent, &m_len);
+ if (!entry) {
+ if (feof(f))
+ break;
+ if (ferror(f)) {
+- warn(LOGOPT_ANY, MODPREFIX
++ warn(ap->logopt, MODPREFIX
+ "error reading map %s", ctxt->mapname);
+ break;
+ }
+@@ -791,7 +791,7 @@ static int lookup_one(struct autofs_point *ap,
+ }
+
+ while(1) {
+- entry = read_one(f, mkey, &k_len, mapent, &m_len);
++ entry = read_one(ap->logopt, f, mkey, &k_len, mapent, &m_len);
+ if (entry) {
+ /*
+ * If key starts with '+' it has to be an
+@@ -860,7 +860,7 @@ static int lookup_one(struct autofs_point *ap,
+ break;
+
+ if (ferror(f)) {
+- warn(LOGOPT_ANY, MODPREFIX
++ warn(ap->logopt, MODPREFIX
+ "error reading map %s", ctxt->mapname);
+ break;
+ }
+@@ -904,7 +904,7 @@ static int lookup_wild(struct autofs_point *ap, struct lookup_context *ctxt)
+ }
+
+ while(1) {
+- entry = read_one(f, mkey, &k_len, mapent, &m_len);
++ entry = read_one(ap->logopt, f, mkey, &k_len, mapent, &m_len);
+ if (entry) {
+ int eq;
+
+@@ -925,7 +925,7 @@ static int lookup_wild(struct autofs_point *ap, struct lookup_context *ctxt)
+ break;
+
+ if (ferror(f)) {
+- warn(LOGOPT_ANY, MODPREFIX
++ warn(ap->logopt, MODPREFIX
+ "error reading map %s", ctxt->mapname);
+ break;
+ }
+diff --git a/modules/lookup_hesiod.c b/modules/lookup_hesiod.c
+index f30e9b2..649e24c 100644
+--- a/modules/lookup_hesiod.c
++++ b/modules/lookup_hesiod.c
+@@ -48,7 +48,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt = malloc(sizeof(struct lookup_context));
+ if (!ctxt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return 1;
+ }
+
+@@ -58,7 +58,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ /* Initialize the hesiod context. */
+ if (hesiod_init(&(ctxt->hesiod_context)) != 0) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "hesiod_init(): %s", estr);
++ logerr(MODPREFIX "hesiod_init(): %s", estr);
+ free(ctxt);
+ return 1;
+ }
+@@ -70,7 +70,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ /* Open the parser, if we can. */
+ ctxt->parser = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parser) {
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
++ logerr(MODPREFIX "failed to open parse context");
+ free(ctxt);
+ return 1;
+ }
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index d711611..d746e42 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -57,7 +57,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt = malloc(sizeof(struct lookup_context));
+ if (!ctxt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return 1;
+ }
+
+@@ -65,7 +65,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc, argv);
+ if (!ctxt->parse) {
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
++ logerr(MODPREFIX "failed to open parse context");
+ free(ctxt);
+ return 1;
+ }
+@@ -94,7 +94,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+
+ status = pthread_mutex_lock(&hostent_mutex);
+ if (status) {
+- error(LOGOPT_ANY, MODPREFIX "failed to lock hostent mutex");
++ error(ap->logopt, MODPREFIX "failed to lock hostent mutex");
+ return NSS_STATUS_UNAVAIL;
+ }
+
+@@ -110,7 +110,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+
+ status = pthread_mutex_unlock(&hostent_mutex);
+ if (status)
+- error(LOGOPT_ANY, MODPREFIX "failed to unlock hostent mutex");
++ error(ap->logopt, MODPREFIX "failed to unlock hostent mutex");
+
+ source->age = age;
+
+@@ -157,10 +157,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ }
+
+ if (*name == '/')
+- msg(MODPREFIX
++ info(ap->logopt, MODPREFIX
+ "can't find path in hosts map %s", name);
+ else
+- msg(MODPREFIX
++ info(ap->logopt, MODPREFIX
+ "can't find path in hosts map %s/%s",
+ ap->path, name);
+
+@@ -216,7 +216,7 @@ done:
+ if (!mapent) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(ap->logopt, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ rpc_exports_free(exp);
+ return NSS_STATUS_UNAVAIL;
+ }
+@@ -230,7 +230,7 @@ done:
+ if (!mapent) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(ap->logopt, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ rpc_exports_free(exp);
+ return NSS_STATUS_UNAVAIL;
+ }
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index c0f228b..00215af 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -49,9 +49,9 @@ static struct ldap_schema common_schema[] = {
+ };
+ static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema);
+
+-static LDAP *auth_init(const char *, struct lookup_context *);
++static LDAP *auth_init(unsigned logopt, const char *, struct lookup_context *);
+
+-int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
++int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ {
+ int rv;
+
+@@ -62,15 +62,14 @@ int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
+
+ if (rv != LDAP_SUCCESS) {
+ if (!ctxt->uri) {
+- crit(LOGOPT_ANY,
+- MODPREFIX "Unable to bind to the LDAP server: "
++ crit(logopt, MODPREFIX
++ "Unable to bind to the LDAP server: "
+ "%s, error %s", ctxt->server ? "" : "(default)",
+ ldap_err2string(rv));
+ } else {
+ struct ldap_uri *uri;
+ uri = list_entry(ctxt->uri->next, struct ldap_uri, list);
+- warn(LOGOPT_ANY,
+- MODPREFIX "Unable to bind to the LDAP server: "
++ info(logopt, MODPREFIX "Unable to bind to the LDAP server: "
+ "%s, error %s", uri->uri, ldap_err2string(rv));
+ }
+ return -1;
+@@ -79,12 +78,11 @@ int bind_ldap_anonymous(LDAP *ldap, struct lookup_context *ctxt)
+ return 0;
+ }
+
+-int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt)
++int unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ {
+ int rv;
+
+ #ifdef WITH_SASL
+- debug(LOGOPT_NONE, "use_tls: %d", ctxt->use_tls);
+ /*
+ * The OpenSSL library can't handle having its message and error
+ * string database loaded multiple times and segfaults if the
+@@ -102,13 +100,12 @@ int unbind_ldap_connection(LDAP *ldap, struct lookup_context *ctxt)
+
+ rv = ldap_unbind_ext(ldap, NULL, NULL);
+ if (rv != LDAP_SUCCESS)
+- error(LOGOPT_ANY,
+- "unbind failed: %s", ldap_err2string(rv));
++ error(logopt, "unbind failed: %s", ldap_err2string(rv));
+
+ return rv;
+ }
+
+-LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
++LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt)
+ {
+ LDAP *ldap = NULL;
+ struct timeval timeout = { ctxt->timeout, 0 };
+@@ -120,9 +117,9 @@ LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
+ /* Initialize the LDAP context. */
+ rv = ldap_initialize(&ldap, uri);
+ if (rv != LDAP_OPT_SUCCESS) {
+- crit(LOGOPT_ANY,
+- MODPREFIX "couldn't initialize LDAP connection to %s",
+- uri ? uri : "default server");
++ info(logopt, MODPREFIX
++ "couldn't initialize LDAP connection to %s",
++ uri ? uri : "default");
+ return NULL;
+ }
+
+@@ -133,7 +130,7 @@ LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
+ ldap_unbind_ext(ldap, NULL, NULL);
+ rv = ldap_initialize(&ldap, uri);
+ if (rv != LDAP_OPT_SUCCESS) {
+- crit(LOGOPT_ANY, MODPREFIX "couldn't initialize LDAP");
++ crit(logopt, MODPREFIX "couldn't initialize LDAP");
+ return NULL;
+ }
+ ctxt->version = 2;
+@@ -144,7 +141,7 @@ LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
+ /* Set synchronous call timeout */
+ rv = ldap_set_option(ldap, LDAP_OPT_TIMEOUT, &timeout);
+ if (rv != LDAP_OPT_SUCCESS)
+- info(LOGOPT_ANY, MODPREFIX
++ info(logopt, MODPREFIX
+ "failed to set synchronous call timeout to %d",
+ timeout.tv_sec);
+ }
+@@ -152,16 +149,14 @@ LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
+ /* Sane network timeout */
+ rv = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &net_timeout);
+ if (rv != LDAP_OPT_SUCCESS)
+- info(LOGOPT_ANY,
+- MODPREFIX "failed to set connection timeout to %d",
++ info(logopt, MODPREFIX "failed to set connection timeout to %d",
+ net_timeout.tv_sec);
+
+ #ifdef WITH_SASL
+ if (ctxt->use_tls) {
+ if (ctxt->version == 2) {
+ if (ctxt->tls_required) {
+- error(LOGOPT_ANY,
+- MODPREFIX
++ error(logopt, MODPREFIX
+ "TLS required but connection is version 2");
+ ldap_unbind_ext(ldap, NULL, NULL);
+ return NULL;
+@@ -171,16 +166,15 @@ LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
+
+ rv = ldap_start_tls_s(ldap, NULL, NULL);
+ if (rv != LDAP_SUCCESS) {
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(logopt, ldap, ctxt);
+ if (ctxt->tls_required) {
+- error(LOGOPT_ANY,
+- MODPREFIX
++ error(logopt, MODPREFIX
+ "TLS required but START_TLS failed: %s",
+ ldap_err2string(rv));
+ return NULL;
+ }
+ ctxt->use_tls = LDAP_TLS_DONT_USE;
+- ldap = init_ldap_connection(uri, ctxt);
++ ldap = init_ldap_connection(logopt, uri, ctxt);
+ if (ldap)
+ ctxt->use_tls = LDAP_TLS_INIT;
+ return ldap;
+@@ -192,7 +186,7 @@ LDAP *init_ldap_connection(const char *uri, struct lookup_context *ctxt)
+ return ldap;
+ }
+
+-static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
++static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
+ {
+ char buf[PARSE_MAX_BUF];
+ char *query, *dn, *qdn;
+@@ -206,7 +200,7 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ attrs[1] = NULL;
+
+ if (!ctxt->mapname && !ctxt->base) {
+- error(LOGOPT_ANY, MODPREFIX "no master map to lookup");
++ error(logopt, MODPREFIX "no master map to lookup");
+ return 0;
+ }
+
+@@ -218,7 +212,7 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ query = alloca(l);
+ if (query == NULL) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
++ crit(logopt, MODPREFIX "alloca: %s", estr);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+@@ -229,14 +223,14 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ if (ctxt->mapname) {
+ if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
+ key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ MODPREFIX "error forming query string");
+ return 0;
+ }
+ scope = LDAP_SCOPE_SUBTREE;
+ } else {
+ if (sprintf(query, "(objectclass=%s)", class) >= l) {
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ MODPREFIX "error forming query string");
+ return 0;
+ }
+@@ -259,15 +253,14 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ else {
+ struct ldap_searchdn *this = ctxt->sdns;
+
+- debug(LOGOPT_NONE, MODPREFIX
+- "check search base list");
++ debug(logopt, MODPREFIX "check search base list");
+
+ while (this) {
+ rv = ldap_search_s(ldap, this->basedn,
+ scope, query, attrs, 0, &result);
+
+ if ((rv == LDAP_SUCCESS) && result) {
+- debug(LOGOPT_NONE, MODPREFIX
++ debug(logopt, MODPREFIX
+ "found search base under %s",
+ this->basedn);
+ break;
+@@ -283,7 +276,7 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ }
+
+ if ((rv != LDAP_SUCCESS) || !result) {
+- error(LOGOPT_NONE,
++ error(logopt,
+ MODPREFIX "query failed for %s: %s",
+ query, ldap_err2string(rv));
+ return 0;
+@@ -292,9 +285,9 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ e = ldap_first_entry(ldap, result);
+ if (e) {
+ dn = ldap_get_dn(ldap, e);
+- debug(LOGOPT_NONE, MODPREFIX "found query dn %s", dn);
++ debug(logopt, MODPREFIX "found query dn %s", dn);
+ } else {
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ MODPREFIX "query succeeded, no matches for %s",
+ query);
+ ldap_msgfree(result);
+@@ -373,7 +366,7 @@ static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
+ return schema;
+ }
+
+-static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
++static int find_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ {
+ struct ldap_schema *schema;
+ unsigned int i;
+@@ -384,11 +377,10 @@ static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
+ for (i = 0; i < common_schema_count; i++) {
+ const char *class = common_schema[i].map_class;
+ const char *key = common_schema[i].map_attr;
+- if (get_query_dn(ldap, ctxt, class, key)) {
++ if (get_query_dn(logopt, ldap, ctxt, class, key)) {
+ schema = alloc_common_schema(&common_schema[i]);
+ if (!schema) {
+- error(LOGOPT_ANY,
+- MODPREFIX "failed to allocate schema");
++ error(logopt, MODPREFIX "failed to allocate schema");
+ return 0;
+ }
+ ctxt->schema = schema;
+@@ -399,28 +391,26 @@ static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
+ return 0;
+ }
+
+-static int do_bind(LDAP *ldap, struct lookup_context *ctxt)
++static int do_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+ {
+ char *host = NULL, *nhost;
+ int rv, need_base = 1;
+
+ #ifdef WITH_SASL
+- debug(LOGOPT_NONE, "auth_required: %d, sasl_mech %s",
++ debug(logopt, MODPREFIX "auth_required: %d, sasl_mech %s",
+ ctxt->auth_required, ctxt->sasl_mech);
+
+ if (ctxt->sasl_mech ||
+ (ctxt->auth_required & (LDAP_AUTH_REQUIRED|LDAP_AUTH_AUTODETECT))) {
+- rv = autofs_sasl_bind(ldap, ctxt);
+- debug(LOGOPT_NONE, MODPREFIX
+- "autofs_sasl_bind returned %d", rv);
++ rv = autofs_sasl_bind(logopt, ldap, ctxt);
++ debug(logopt, MODPREFIX "autofs_sasl_bind returned %d", rv);
+ } else {
+- rv = bind_ldap_anonymous(ldap, ctxt);
+- debug(LOGOPT_NONE,
+- MODPREFIX "ldap anonymous bind returned %d", rv);
++ rv = bind_ldap_anonymous(logopt, ldap, ctxt);
++ debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
+ }
+ #else
+- rv = bind_ldap_anonymous(ldap, ctxt);
+- debug(LOGOPT_NONE, MODPREFIX "ldap anonymous bind returned %d", rv);
++ rv = bind_ldap_anonymous(logopt, ldap, ctxt);
++ debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
+ #endif
+
+ if (rv != 0)
+@@ -428,13 +418,13 @@ static int do_bind(LDAP *ldap, struct lookup_context *ctxt)
+
+ rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
+ if (rv != LDAP_SUCCESS || !host) {
+- debug(LOGOPT_ANY, "failed to get hostname for connection");
++ debug(logopt, "failed to get hostname for connection");
+ return 0;
+ }
+
+ nhost = strdup(host);
+ if (!nhost) {
+- debug(LOGOPT_ANY, "failed to alloc context for hostname");
++ debug(logopt, "failed to alloc context for hostname");
+ return 0;
+ }
+ ldap_memfree(host);
+@@ -463,16 +453,16 @@ static int do_bind(LDAP *ldap, struct lookup_context *ctxt)
+ * base dn for searches.
+ */
+ if (!ctxt->schema) {
+- if (!find_query_dn(ldap, ctxt)) {
+- error(LOGOPT_ANY,
+- MODPREFIX "failed to find valid query dn");
++ if (!find_query_dn(logopt, ldap, ctxt)) {
++ warn(logopt,
++ MODPREFIX "failed to find valid query dn");
+ return 0;
+ }
+ } else {
+ const char *class = ctxt->schema->map_class;
+ const char *key = ctxt->schema->map_attr;
+- if (!get_query_dn(ldap, ctxt, class, key)) {
+- error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
++ if (!get_query_dn(logopt, ldap, ctxt, class, key)) {
++ error(logopt, MODPREFIX "failed to get query dn");
+ return 0;
+ }
+ }
+@@ -480,23 +470,23 @@ static int do_bind(LDAP *ldap, struct lookup_context *ctxt)
+ return 1;
+ }
+
+-static LDAP *do_connect(const char *uri, struct lookup_context *ctxt)
++static LDAP *do_connect(unsigned logopt, const char *uri, struct lookup_context *ctxt)
+ {
+ LDAP *ldap;
+
+- ldap = init_ldap_connection(uri, ctxt);
++ ldap = init_ldap_connection(logopt, uri, ctxt);
+ if (!ldap)
+ return NULL;
+
+- if (!do_bind(ldap, ctxt)) {
+- unbind_ldap_connection(ldap, ctxt);
++ if (!do_bind(logopt, ldap, ctxt)) {
++ unbind_ldap_connection(logopt, ldap, ctxt);
+ return NULL;
+ }
+
+ return ldap;
+ }
+
+-static LDAP *connect_to_server(const char *uri, struct lookup_context *ctxt)
++static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_context *ctxt)
+ {
+ LDAP *ldap;
+
+@@ -506,19 +496,19 @@ static LDAP *connect_to_server(const char *uri, struct lookup_context *ctxt)
+ * authentication.
+ */
+ if (ctxt->auth_required & LDAP_AUTH_REQUIRED) {
+- ldap = auth_init(uri, ctxt);
++ ldap = auth_init(logopt, uri, ctxt);
+ if (!ldap && ctxt->auth_required & LDAP_AUTH_AUTODETECT)
+- warn(LOGOPT_NONE,
++ info(logopt,
+ "no authentication mechanisms auto detected.");
+ if (!ldap) {
+- error(LOGOPT_ANY, MODPREFIX
++ error(logopt, MODPREFIX
+ "cannot initialize authentication setup");
+ return NULL;
+ }
+
+- if (!do_bind(ldap, ctxt)) {
+- unbind_ldap_connection(ldap, ctxt);
+- error(LOGOPT_ANY, MODPREFIX "cannot bind to server");
++ if (!do_bind(logopt, ldap, ctxt)) {
++ unbind_ldap_connection(logopt, ldap, ctxt);
++ error(logopt, MODPREFIX "cannot bind to server");
+ return NULL;
+ }
+
+@@ -526,16 +516,18 @@ static LDAP *connect_to_server(const char *uri, struct lookup_context *ctxt)
+ }
+ #endif
+
+- ldap = do_connect(uri, ctxt);
++ ldap = do_connect(logopt, uri, ctxt);
+ if (!ldap) {
+- error(LOGOPT_ANY, MODPREFIX "cannot connect to server");
++ warn(logopt,
++ MODPREFIX "couldn't connect to server %s",
++ uri ? uri : "default");
+ return NULL;
+ }
+
+ return ldap;
+ }
+
+-static LDAP *find_server(struct lookup_context *ctxt)
++static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
+ {
+ LDAP *ldap = NULL;
+ struct ldap_uri *this;
+@@ -547,10 +539,9 @@ static LDAP *find_server(struct lookup_context *ctxt)
+ while(p != ctxt->uri) {
+ this = list_entry(p, struct ldap_uri, list);
+ p = p->next;
+- debug(LOGOPT_ANY, "check uri %s", this->uri);
+- ldap = connect_to_server(this->uri, ctxt);
++ ldap = connect_to_server(logopt, this->uri, ctxt);
+ if (ldap) {
+- debug(LOGOPT_ANY, "connexted to uri %s", this->uri);
++ info(logopt, "connected to uri %s", this->uri);
+ break;
+ }
+ list_del_init(&this->list);
+@@ -568,17 +559,17 @@ static LDAP *find_server(struct lookup_context *ctxt)
+ return ldap;
+ }
+
+-static LDAP *do_reconnect(struct lookup_context *ctxt)
++static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
+ {
+ LDAP *ldap;
+
+ if (ctxt->server || !ctxt->uri) {
+- ldap = do_connect(ctxt->server, ctxt);
++ ldap = do_connect(logopt, ctxt->server, ctxt);
+ return ldap;
+ } else {
+ struct ldap_uri *this;
+ this = list_entry(ctxt->uri->next, struct ldap_uri, list);
+- ldap = do_connect(this->uri, ctxt);
++ ldap = do_connect(logopt, this->uri, ctxt);
+ if (ldap)
+ return ldap;
+ /* Failed to connect, put at end of list */
+@@ -589,15 +580,15 @@ static LDAP *do_reconnect(struct lookup_context *ctxt)
+ autofs_sasl_done(ctxt);
+
+ /* Current server failed connect, try the rest */
+- ldap = find_server(ctxt);
++ ldap = find_server(logopt, ctxt);
+ if (!ldap)
+- error(LOGOPT_ANY, MODPREFIX "failed to find available server");
++ error(logopt, MODPREFIX "failed to find available server");
+
+ return ldap;
+ }
+
+ #ifdef WITH_SASL
+-int get_property(xmlNodePtr node, const char *prop, char **value)
++int get_property(unsigned logopt, xmlNodePtr node, const char *prop, char **value)
+ {
+ xmlChar *ret;
+ xmlChar *property = (xmlChar *) prop;
+@@ -608,8 +599,7 @@ int get_property(xmlNodePtr node, const char *prop, char **value)
+ }
+
+ if (!(*value = strdup((char *) ret))) {
+- error(LOGOPT_ANY,
+- MODPREFIX "strdup failed with %d", errno);
++ logerr(MODPREFIX "strdup failed with %d", errno);
+ xmlFree(ret);
+ return -1;
+ }
+@@ -645,7 +635,7 @@ int authtype_requires_creds(const char *authtype)
+ * then no further action is necessary. If it is not, the caller is free
+ * to then use another method to determine how to connect to the server.
+ */
+-int parse_ldap_config(struct lookup_context *ctxt)
++int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
+ {
+ int ret = 0, fallback = 0;
+ unsigned int auth_required = LDAP_AUTH_NOTREQUIRED;
+@@ -662,7 +652,7 @@ int parse_ldap_config(struct lookup_context *ctxt)
+
+ auth_conf = (char *) defaults_get_auth_conf_file();
+ if (!auth_conf) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX "failed to get auth config file name.");
+ return 0;
+ }
+@@ -687,7 +677,7 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ ctxt->client_princ = NULL;
+ return 0;
+ }
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX "stat(2) failed with error %s.",
+ strerror(errno));
+ return 0;
+@@ -696,8 +686,7 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ if (!S_ISREG(st.st_mode) ||
+ st.st_uid != 0 || st.st_gid != 0 ||
+ (st.st_mode & 0x01ff) != 0600) {
+- error(LOGOPT_ANY,
+- MODPREFIX
++ error(logopt, MODPREFIX
+ "Configuration file %s exists, but is not usable. "
+ "Please make sure that it is owned by root, group "
+ "is root, and the mode is 0600.",
+@@ -708,30 +697,29 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ xmlInitParser();
+ doc = xmlParseFile(auth_conf);
+ if (!doc) {
+- warn(LOGOPT_ANY,
+- MODPREFIX "xmlParseFile failed for %s.", auth_conf);
++ error(logopt, MODPREFIX
++ "xmlParseFile failed for %s.", auth_conf);
+ goto out;
+ }
+
+ root = xmlDocGetRootElement(doc);
+ if (!root) {
+- debug(LOGOPT_ANY,
+- MODPREFIX "empty xml document (%s).", auth_conf);
++ debug(logopt, MODPREFIX
++ "empty xml document (%s).", auth_conf);
+ fallback = 1;
+ goto out;
+ }
+
+ if (xmlStrcmp(root->name, (const xmlChar *)"autofs_ldap_sasl_conf")) {
+- error(LOGOPT_ANY,
+- MODPREFIX
++ error(logopt, MODPREFIX
+ "The root node of the XML document %s is not "
+ "autofs_ldap_sasl_conf.", auth_conf);
+ goto out;
+ }
+
+- ret = get_property(root, "usetls", &usetls);
++ ret = get_property(logopt, root, "usetls", &usetls);
+ if (ret != 0) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "Failed read the usetls property from "
+ "the configuration file %s.", auth_conf);
+@@ -746,7 +734,7 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ else if (!strcasecmp(usetls, "no"))
+ use_tls = LDAP_TLS_DONT_USE;
+ else {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "The usetls property must have value "
+ "\"yes\" or \"no\".");
+@@ -756,9 +744,9 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ free(usetls);
+ }
+
+- ret = get_property(root, "tlsrequired", &tlsrequired);
++ ret = get_property(logopt, root, "tlsrequired", &tlsrequired);
+ if (ret != 0) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "Failed read the tlsrequired property from "
+ "the configuration file %s.", auth_conf);
+@@ -773,7 +761,7 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ else if (!strcasecmp(tlsrequired, "no"))
+ tls_required = LDAP_TLS_DONT_USE;
+ else {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "The tlsrequired property must have value "
+ "\"yes\" or \"no\".");
+@@ -783,9 +771,9 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ free(tlsrequired);
+ }
+
+- ret = get_property(root, "authrequired", &authrequired);
++ ret = get_property(logopt, root, "authrequired", &authrequired);
+ if (ret != 0) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "Failed read the authrequired property from "
+ "the configuration file %s.", auth_conf);
+@@ -802,7 +790,7 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ else if (!strcasecmp(authrequired, "autodetect"))
+ auth_required = LDAP_AUTH_AUTODETECT;
+ else {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "The authrequired property must have value "
+ "\"yes\", \"no\" or \"autodetect\".");
+@@ -812,9 +800,9 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ free(authrequired);
+ }
+
+- ret = get_property(root, "authtype", &authtype);
++ ret = get_property(logopt, root, "authtype", &authtype);
+ if (ret != 0) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "Failed read the authtype property from the "
+ "configuration file %s.", auth_conf);
+@@ -822,10 +810,10 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ }
+
+ if (authtype && authtype_requires_creds(authtype)) {
+- ret = get_property(root, "user", &user);
+- ret |= get_property(root, "secret", &secret);
++ ret = get_property(logopt, root, "user", &user);
++ ret |= get_property(logopt, root, "secret", &secret);
+ if (ret != 0 || (!user || !secret)) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "%s authentication type requires a username "
+ "and a secret. Please fix your configuration "
+@@ -845,7 +833,7 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ * We allow the admin to specify the principal to use for the
+ * client. The default is "autofsclient/hostname@REALM".
+ */
+- (void)get_property(root, "clientprinc", &client_princ);
++ (void)get_property(logopt, root, "clientprinc", &client_princ);
+
+ ctxt->auth_conf = auth_conf;
+ ctxt->use_tls = use_tls;
+@@ -856,15 +844,15 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ ctxt->secret = secret;
+ ctxt->client_princ = client_princ;
+
+- debug(LOGOPT_NONE,
++ debug(logopt, MODPREFIX
+ "ldap authentication configured with the following options:");
+- debug(LOGOPT_NONE,
++ debug(logopt, MODPREFIX
+ "use_tls: %u, "
+ "tls_required: %u, "
+ "auth_required: %u, "
+ "sasl_mech: %s",
+ use_tls, tls_required, auth_required, authtype);
+- debug(LOGOPT_NONE,
++ debug(logopt, MODPREFIX
+ "user: %s, "
+ "secret: %s, "
+ "client principal: %s",
+@@ -889,7 +877,7 @@ out:
+ * Returns ldap connection on success, with authtype, user and secret
+ * filled in as appropriate. Returns NULL on failre.
+ */
+-static LDAP *auth_init(const char *uri, struct lookup_context *ctxt)
++static LDAP *auth_init(unsigned logopt, const char *uri, struct lookup_context *ctxt)
+ {
+ int ret;
+ LDAP *ldap;
+@@ -900,11 +888,11 @@ static LDAP *auth_init(const char *uri, struct lookup_context *ctxt)
+ * if the permissions on the file were incorrect, or if the
+ * specified authentication type is not valid.
+ */
+- ret = parse_ldap_config(ctxt);
++ ret = parse_ldap_config(logopt, ctxt);
+ if (ret)
+ return NULL;
+
+- ldap = init_ldap_connection(uri, ctxt);
++ ldap = init_ldap_connection(logopt, uri, ctxt);
+ if (!ldap)
+ return NULL;
+
+@@ -916,7 +904,7 @@ static LDAP *auth_init(const char *uri, struct lookup_context *ctxt)
+ * to use. If kerberos is used, it will also take care to initialize
+ * the credential cache and the client and service principals.
+ */
+- ret = autofs_sasl_init(ldap, ctxt);
++ ret = autofs_sasl_init(logopt, ldap, ctxt);
+ if (ret) {
+ ctxt->sasl_mech = NULL;
+ return NULL;
+@@ -930,7 +918,7 @@ static LDAP *auth_init(const char *uri, struct lookup_context *ctxt)
+ * Take an input string as specified in the master map, and break it
+ * down into a server name and basedn.
+ */
+-static int parse_server_string(const char *url, struct lookup_context *ctxt)
++static int parse_server_string(unsigned logopt, const char *url, struct lookup_context *ctxt)
+ {
+ char buf[MAX_ERR_BUF], *tmp = NULL, proto[9];
+ const char *ptr, *name;
+@@ -939,8 +927,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ memset(proto, 0, 9);
+ ptr = url;
+
+- debug(LOGOPT_NONE,
+- MODPREFIX
++ debug(logopt, MODPREFIX
+ "Attempting to parse LDAP information from string \"%s\".", ptr);
+
+ ctxt->port = LDAP_PORT;
+@@ -974,7 +961,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ if (!tmp) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return 0;
+ }
+ ctxt->server = tmp;
+@@ -987,7 +974,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ memcpy(ctxt->server, s, l);
+ ptr = q + 1;
+ } else {
+- crit(LOGOPT_ANY,
++ crit(logopt,
+ MODPREFIX "invalid LDAP map syntax %s", ptr);
+ return 0;
+ /* TODO: why did I put this here, the parser shouldn't let this by
+@@ -996,7 +983,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ if (!tmp) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ crit(logopt, MODPREFIX "malloc: %s", estr);
+ return 0;
+ }
+ ctxt->server = tmp;
+@@ -1014,7 +1001,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ q++;
+
+ if (*q != ':') {
+- crit(LOGOPT_ANY,
++ crit(logopt,
+ MODPREFIX "invalid LDAP map syntax %s", ptr);
+ return 0;
+ }
+@@ -1031,7 +1018,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ if (!tmp) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return 0;
+ }
+ ctxt->server = tmp;
+@@ -1072,7 +1059,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ else {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ if (ctxt->server)
+ free(ctxt->server);
+ return 0;
+@@ -1083,7 +1070,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ if (!base) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ if (ctxt->server)
+ free(ctxt->server);
+ return 0;
+@@ -1097,7 +1084,7 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+ if (!map) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ if (ctxt->server)
+ free(ctxt->server);
+ return 0;
+@@ -1109,16 +1096,16 @@ static int parse_server_string(const char *url, struct lookup_context *ctxt)
+
+ if (!ctxt->server && *proto) {
+ if (!strncmp(proto, "ldaps", 5)) {
+- warn(LOGOPT_ANY, MODPREFIX
++ info(logopt, MODPREFIX
+ "server must be given to force ldaps, connection "
+ "will use LDAP client configured protocol");
+ }
+ }
+ done:
+ if (ctxt->mapname)
+- debug(LOGOPT_NONE, MODPREFIX "mapname %s", ctxt->mapname);
++ debug(logopt, MODPREFIX "mapname %s", ctxt->mapname);
+ else
+- debug(LOGOPT_NONE, MODPREFIX "server \"%s\", base dn \"%s\"",
++ debug(logopt, MODPREFIX "server \"%s\", base dn \"%s\"",
+ ctxt->server ? ctxt->server : "(default)",
+ ctxt->base);
+
+@@ -1175,8 +1162,6 @@ static void validate_uris(struct list_head *list)
+
+ /* At least we get some basic validation */
+ if (!ldap_is_ldap_url(this->uri)) {
+- warn(LOGOPT_ANY,
+- "removed invalid uri from list, %s", this->uri);
+ list_del(&this->list);
+ free(this->uri);
+ free(this);
+@@ -1202,7 +1187,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt = malloc(sizeof(struct lookup_context));
+ if (!ctxt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return 1;
+ }
+ memset(ctxt, 0, sizeof(struct lookup_context));
+@@ -1215,7 +1200,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ * Parse out the server name and base dn, and fill them
+ * into the proper places in the lookup context structure.
+ */
+- if (!parse_server_string(argv[0], ctxt)) {
++ if (!parse_server_string(LOGOPT_NONE, argv[0], ctxt)) {
+ error(LOGOPT_ANY, MODPREFIX "cannot parse server string");
+ free_context(ctxt);
+ return 1;
+@@ -1236,13 +1221,13 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ }
+
+ if (ctxt->server || !ctxt->uri) {
+- ldap = connect_to_server(ctxt->server, ctxt);
++ ldap = connect_to_server(LOGOPT_NONE, ctxt->server, ctxt);
+ if (!ldap) {
+ free_context(ctxt);
+ return 1;
+ }
+ } else {
+- ldap = find_server(ctxt);
++ ldap = find_server(LOGOPT_NONE, ctxt);
+ if (!ldap) {
+ free_context(ctxt);
+ error(LOGOPT_ANY, MODPREFIX
+@@ -1250,13 +1235,13 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ return 1;
+ }
+ }
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt);
+
+ /* Open the parser, if we can. */
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parse) {
+ free_context(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
++ logerr(MODPREFIX "failed to open parse context");
+ return 1;
+ }
+ *context = ctxt;
+@@ -1269,6 +1254,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ unsigned int timeout = master->default_timeout;
+ unsigned int logging = master->default_logging;
++ unsigned int logopt = master->logopt;
+ int rv, l, count, blen;
+ char buf[PARSE_MAX_BUF];
+ char *query;
+@@ -1293,45 +1279,44 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ query = alloca(l);
+ if (query == NULL) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ if (sprintf(query, "(objectclass=%s)", class) >= l) {
+- debug(LOGOPT_NONE, MODPREFIX "error forming query string");
++ error(logopt, MODPREFIX "error forming query string");
+ return NSS_STATUS_UNAVAIL;
+ }
+ query[l] = '\0';
+
+ /* Initialize the LDAP context. */
+- ldap = do_reconnect(ctxt);
++ ldap = do_reconnect(logopt, ctxt);
+ if (!ldap)
+ return NSS_STATUS_UNAVAIL;
+
+ /* Look around. */
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn);
+
+ rv = ldap_search_s(ldap, ctxt->qdn, scope, query, attrs, 0, &result);
+
+ if ((rv != LDAP_SUCCESS) || !result) {
+- error(LOGOPT_NONE,
+- MODPREFIX "query failed for %s: %s",
++ error(logopt, MODPREFIX "query failed for %s: %s",
+ query, ldap_err2string(rv));
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(logging, ldap, ctxt);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ e = ldap_first_entry(ldap, result);
+ if (!e) {
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ MODPREFIX "query succeeded, no matches for %s",
+ query);
+ ldap_msgfree(result);
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(logging, ldap, ctxt);
+ return NSS_STATUS_NOTFOUND;
+ } else
+- debug(LOGOPT_NONE, MODPREFIX "examining entries");
++ debug(logopt, MODPREFIX "examining entries");
+
+ while (e) {
+ keyValue = ldap_get_values(ldap, e, entry);
+@@ -1346,7 +1331,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ * each map entry
+ */
+ if (ldap_count_values(keyValue) > 1) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "key %s has duplicate entries - ignoring",
+ *keyValue);
+@@ -1358,7 +1343,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ * inclusion is only valid in file maps.
+ */
+ if (**keyValue == '+') {
+- warn(LOGOPT_ANY,
++ warn(logopt,
+ MODPREFIX
+ "ignoreing '+' map entry - not in file map");
+ goto next;
+@@ -1366,7 +1351,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+
+ values = ldap_get_values(ldap, e, info);
+ if (!values || !*values) {
+- debug(LOGOPT_NONE,
++ debug(logopt,
+ MODPREFIX "no %s defined for %s", info, query);
+ goto next;
+ }
+@@ -1376,7 +1361,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ */
+ count = ldap_count_values(values);
+ if (count > 1) {
+- error(LOGOPT_ANY,
++ error(logopt,
+ MODPREFIX
+ "one value per key allowed in master map");
+ ldap_value_free(values);
+@@ -1385,7 +1370,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+
+ blen = strlen(*keyValue) + 1 + strlen(*values) + 1;
+ if (blen > PARSE_MAX_BUF) {
+- error(LOGOPT_ANY, MODPREFIX "map entry too long");
++ error(logopt, MODPREFIX "map entry too long");
+ ldap_value_free(values);
+ goto next;
+ }
+@@ -1403,7 +1388,7 @@ next:
+
+ /* Clean up. */
+ ldap_msgfree(result);
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(logopt, ldap, ctxt);
+
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -1445,7 +1430,7 @@ static int read_one_map(struct autofs_point *ap,
+ query = alloca(l);
+ if (query == NULL) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+@@ -1456,7 +1441,7 @@ static int read_one_map(struct autofs_point *ap,
+ query[l] = '\0';
+
+ /* Initialize the LDAP context. */
+- ldap = do_reconnect(ctxt);
++ ldap = do_reconnect(ap->logopt, ctxt);
+ if (!ldap)
+ return NSS_STATUS_UNAVAIL;
+
+@@ -1470,7 +1455,7 @@ static int read_one_map(struct autofs_point *ap,
+ debug(ap->logopt,
+ MODPREFIX "query failed for %s: %s",
+ query, ldap_err2string(rv));
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(ap->logopt, ldap, ctxt);
+ *result_ldap = rv;
+ return NSS_STATUS_NOTFOUND;
+ }
+@@ -1480,7 +1465,7 @@ static int read_one_map(struct autofs_point *ap,
+ debug(ap->logopt,
+ MODPREFIX "query succeeded, no matches for %s", query);
+ ldap_msgfree(result);
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(ap->logopt, ldap, ctxt);
+ return NSS_STATUS_NOTFOUND;
+ } else
+ debug(ap->logopt, MODPREFIX "examining entries");
+@@ -1612,8 +1597,7 @@ static int read_one_map(struct autofs_point *ap,
+ if (!mapent) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt,
+- MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ ldap_value_free_len(bvValues);
+ goto next;
+ }
+@@ -1633,8 +1617,7 @@ static int read_one_map(struct autofs_point *ap,
+ } else {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt,
+- MODPREFIX "realloc: %s", estr);
++ logerr(MODPREFIX "realloc: %s", estr);
+ }
+ }
+ }
+@@ -1669,7 +1652,7 @@ next:
+
+ /* Clean up. */
+ ldap_msgfree(result);
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(ap->logopt, ldap, ctxt);
+
+ source->age = age;
+
+@@ -1766,7 +1749,7 @@ static int lookup_one(struct autofs_point *ap,
+ query[ql] = '\0';
+
+ /* Initialize the LDAP context. */
+- ldap = do_reconnect(ctxt);
++ ldap = do_reconnect(ap->logopt, ctxt);
+ if (!ldap)
+ return CHE_FAIL;
+
+@@ -1777,7 +1760,7 @@ static int lookup_one(struct autofs_point *ap,
+
+ if ((rv != LDAP_SUCCESS) || !result) {
+ crit(ap->logopt, MODPREFIX "query failed for %s", query);
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(ap->logopt, ldap, ctxt);
+ return CHE_FAIL;
+ }
+
+@@ -1789,7 +1772,7 @@ static int lookup_one(struct autofs_point *ap,
+ debug(ap->logopt,
+ MODPREFIX "got answer, but no entry for %s", query);
+ ldap_msgfree(result);
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(ap->logopt, ldap, ctxt);
+ return CHE_MISSING;
+ }
+
+@@ -1897,8 +1880,7 @@ static int lookup_one(struct autofs_point *ap,
+ if (!mapent) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt,
+- MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ ldap_value_free_len(bvValues);
+ goto next;
+ }
+@@ -1918,8 +1900,7 @@ static int lookup_one(struct autofs_point *ap,
+ } else {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt,
+- MODPREFIX "realloc: %s", estr);
++ logerr(MODPREFIX "realloc: %s", estr);
+ }
+ }
+ }
+@@ -1955,7 +1936,7 @@ next:
+ }
+
+ ldap_msgfree(result);
+- unbind_ldap_connection(ldap, ctxt);
++ unbind_ldap_connection(ap->logopt, ldap, ctxt);
+
+ /* Failed to find wild entry, update cache if needed */
+ pthread_cleanup_push(cache_lock_cleanup, mc);
+diff --git a/modules/lookup_multi.c b/modules/lookup_multi.c
+index 8fa94ae..601d48e 100644
+--- a/modules/lookup_multi.c
++++ b/modules/lookup_multi.c
+@@ -73,7 +73,7 @@ static struct lookup_mod *nss_open_lookup(const char *format, int argc, const ch
+ if (nsswitch_parse(&nsslist)) {
+ if (!list_empty(&nsslist))
+ free_sources(&nsslist);
+- error(LOGOPT_ANY, "can't to read name service switch config.");
++ logerr("can't to read name service switch config.");
+ return NULL;
+ }
+
+@@ -92,7 +92,7 @@ static struct lookup_mod *nss_open_lookup(const char *format, int argc, const ch
+ path = malloc(strlen(AUTOFS_MAP_DIR) + strlen(argv[0]) + 2);
+ if (!path) {
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "error: %s", estr);
++ logerr(MODPREFIX "error: %s", estr);
+ free_sources(&nsslist);
+ return NULL;
+ }
+@@ -150,7 +150,7 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+ memset(ctxt, 0, sizeof(struct lookup_context));
+
+ if (argc < 1) {
+- crit(LOGOPT_ANY, MODPREFIX "No map list");
++ logerr(MODPREFIX "No map list");
+ goto error_out;
+ }
+
+@@ -176,8 +176,7 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+ if (!strcmp(ctxt->argl[an], "--")) {
+ ctxt->argl[an] = NULL;
+ if (!args) {
+- crit(LOGOPT_ANY,
+- MODPREFIX "error assigning map args");
++ logerr(MODPREFIX "error assigning map args");
+ goto error_out;
+ }
+ ctxt->m[i].argv = copy_argv(ctxt->m[i].argc, (const char **) args);
+@@ -201,7 +200,7 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+ ctxt->m[i].mod = nss_open_lookup(my_mapfmt,
+ ctxt->m[i].argc, ctxt->m[i].argv);
+ if (!ctxt->m[i].mod) {
+- error(LOGOPT_ANY, MODPREFIX "error opening module");
++ logerr(MODPREFIX "error opening module");
+ goto error_out;
+ }
+ }
+@@ -211,7 +210,7 @@ int lookup_init(const char *my_mapfmt, int argc, const char *const *argv, void *
+
+ nomem:
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "error: %s", estr);
++ logerr(MODPREFIX "error: %s", estr);
+ error_out:
+ if (ctxt) {
+ for (i = 0; i < ctxt->n; i++) {
+diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
+index 83e99e0..ff8bd49 100644
+--- a/modules/lookup_nisplus.c
++++ b/modules/lookup_nisplus.c
+@@ -41,13 +41,13 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt = malloc(sizeof(struct lookup_context));
+ if (!ctxt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "%s", estr);
++ logerr(MODPREFIX "%s", estr);
+ return 1;
+ }
+
+ if (argc < 1) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "No map name");
++ logmsg(MODPREFIX "No map name");
+ return 1;
+ }
+ ctxt->mapname = argv[0];
+@@ -59,7 +59,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt->domainname = nis_local_directory();
+ if (!ctxt->domainname) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "NIS+ domain not set");
++ logmsg(MODPREFIX "NIS+ domain not set");
+ return 1;
+ }
+
+@@ -69,7 +69,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parse) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
++ logerr(MODPREFIX "failed to open parse context");
+ return 1;
+ }
+ *context = ctxt;
+@@ -81,7 +81,8 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ {
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ unsigned int timeout = master->default_timeout;
+- unsigned int logging = master->default_logging;
++ unsigned int logging = master->default_logging;
++ unsigned int logopt = master->logopt;
+ char *tablename;
+ nis_result *result;
+ nis_object *this;
+@@ -95,7 +96,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ tablename = alloca(strlen(ctxt->mapname) + strlen(ctxt->domainname) + 20);
+ if (!tablename) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_UNAVAIL;
+ }
+@@ -105,8 +106,8 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ result = nis_lookup(tablename, FOLLOW_PATH | FOLLOW_LINKS);
+ if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) {
+ nis_freeresult(result);
+- crit(LOGOPT_ANY,
+- MODPREFIX "couldn't locat nis+ table %s", ctxt->mapname);
++ crit(logopt,
++ MODPREFIX "couldn't locate nis+ table %s", ctxt->mapname);
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_NOTFOUND;
+ }
+@@ -116,7 +117,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ result = nis_list(tablename, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+ if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) {
+ nis_freeresult(result);
+- crit(LOGOPT_ANY,
++ crit(logopt,
+ MODPREFIX "couldn't enumrate nis+ map %s", ctxt->mapname);
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_UNAVAIL;
+@@ -139,8 +140,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+
+ buffer = malloc(ENTRY_LEN(this, 0) + 1 + ENTRY_LEN(this, 1) + 1);
+ if (!buffer) {
+- error(LOGOPT_ANY,
+- MODPREFIX "could not malloc parse buffer");
++ logerr(MODPREFIX "could not malloc parse buffer");
+ continue;
+ }
+
+@@ -182,7 +182,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+ tablename = alloca(strlen(ctxt->mapname) + strlen(ctxt->domainname) + 20);
+ if (!tablename) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_UNAVAIL;
+ }
+@@ -193,7 +193,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+ if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) {
+ nis_freeresult(result);
+ crit(ap->logopt,
+- MODPREFIX "couldn't locat nis+ table %s", ctxt->mapname);
++ MODPREFIX "couldn't locate nis+ table %s", ctxt->mapname);
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_NOTFOUND;
+ }
+@@ -274,7 +274,7 @@ static int lookup_one(struct autofs_point *ap,
+ strlen(ctxt->mapname) + strlen(ctxt->domainname) + 20);
+ if (!tablename) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ pthread_setcancelstate(cur_state, NULL);
+ return -1;
+ }
+@@ -327,7 +327,7 @@ static int lookup_wild(struct autofs_point *ap, struct lookup_context *ctxt)
+ tablename = alloca(strlen(ctxt->mapname) + strlen(ctxt->domainname) + 20);
+ if (!tablename) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ pthread_setcancelstate(cur_state, NULL);
+ return -1;
+ }
+diff --git a/modules/lookup_program.c b/modules/lookup_program.c
+index 2fd521a..e28168e 100644
+--- a/modules/lookup_program.c
++++ b/modules/lookup_program.c
+@@ -51,28 +51,26 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt = malloc(sizeof(struct lookup_context));
+ if (!ctxt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return 1;
+ }
+
+ if (argc < 1) {
+- crit(LOGOPT_ANY, MODPREFIX "No map name");
++ logmsg(MODPREFIX "No map name");
+ free(ctxt);
+ return 1;
+ }
+ ctxt->mapname = argv[0];
+
+ if (ctxt->mapname[0] != '/') {
+- crit(LOGOPT_ANY,
+- MODPREFIX "program map %s is not an absolute pathname",
++ logmsg(MODPREFIX "program map %s is not an absolute pathname",
+ ctxt->mapname);
+ free(ctxt);
+ return 1;
+ }
+
+ if (access(ctxt->mapname, X_OK)) {
+- crit(LOGOPT_ANY,
+- MODPREFIX "program map %s missing or not executable",
++ logmsg(MODPREFIX "program map %s missing or not executable",
+ ctxt->mapname);
+ free(ctxt);
+ return 1;
+@@ -83,7 +81,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parse) {
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
++ logmsg(MODPREFIX "failed to open parse context");
+ free(ctxt);
+ return 1;
+ }
+@@ -163,7 +161,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ mapent = (char *) malloc(MAPENT_MAX_LEN + 1);
+ if (!mapent) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+@@ -176,7 +174,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ */
+ if (pipe(pipefd)) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "pipe: %s", estr);
++ logerr(MODPREFIX "pipe: %s", estr);
+ goto out_free;
+ }
+ if (pipe(epipefd)) {
+@@ -188,7 +186,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ f = fork();
+ if (f < 0) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "fork: %s", estr);
++ logerr(MODPREFIX "fork: %s", estr);
+ close(pipefd[0]);
+ close(pipefd[1]);
+ close(epipefd[0]);
+@@ -271,8 +269,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ ++alloci));
+ if (!tmp) {
+ alloci--;
+- error(ap->logopt,
+- MODPREFIX "realloc: %s",
++ logerr(MODPREFIX "realloc: %s",
+ strerror(errno));
+ break;
+ }
+@@ -308,12 +305,12 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ } else if (ch == '\n') {
+ *errp = '\0';
+ if (errbuf[0])
+- error(ap->logopt, ">> %s", errbuf);
++ logmsg(">> %s", errbuf);
+ errp = errbuf;
+ } else {
+ if (errp >= &errbuf[1023]) {
+ *errp = '\0';
+- error(ap->logopt, ">> %s", errbuf);
++ logmsg(">> %s", errbuf);
+ errp = errbuf;
+ }
+ *(errp++) = ch;
+@@ -325,7 +322,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ *mapp = '\0';
+ if (errp > errbuf) {
+ *errp = '\0';
+- error(ap->logopt, ">> %s", errbuf);
++ logmsg(">> %s", errbuf);
+ }
+
+ close(pipefd[0]);
+@@ -333,12 +330,12 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ if (waitpid(f, &status, 0) != f) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "waitpid: %s", estr);
++ logerr(MODPREFIX "waitpid: %s", estr);
+ goto out_free;
+ }
+
+ if (mapp == mapent || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+- msg(MODPREFIX "lookup for %s failed", name);
++ info(ap->logopt, MODPREFIX "lookup for %s failed", name);
+ goto out_free;
+ }
+
+diff --git a/modules/lookup_userhome.c b/modules/lookup_userhome.c
+index efcab0b..680ddaf 100644
+--- a/modules/lookup_userhome.c
++++ b/modules/lookup_userhome.c
+@@ -73,7 +73,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ /* Create the appropriate symlink */
+ if (chdir(ap->path)) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "chdir failed: %s", estr);
++ logerr(MODPREFIX "chdir failed: %s", estr);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+@@ -88,7 +88,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ if (symlink(pw->pw_dir, name) && errno != EEXIST) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "symlink failed: %s", estr);
++ logerr(MODPREFIX "symlink failed: %s", estr);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index da280cc..63fc8e3 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -45,12 +45,14 @@ struct lookup_context {
+ struct callback_master_data {
+ unsigned timeout;
+ unsigned logging;
++ unsigned logopt;
+ time_t age;
+ };
+
+ struct callback_data {
+ struct autofs_point *ap;
+ struct map_source *source;
++ unsigned logopt;
+ time_t age;
+ };
+
+@@ -111,20 +113,18 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt = malloc(sizeof(struct lookup_context));
+ if (!ctxt) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "%s", estr);
++ logerr(MODPREFIX "%s", estr);
+ return 1;
+ }
+ memset(ctxt, 0, sizeof(struct lookup_context));
+
+ if (argc < 1) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "no map name");
++ logerr(MODPREFIX "no map name");
+ return 1;
+ }
+ ctxt->mapname = argv[0];
+
+- debug(LOGOPT_NONE, MODPREFIX "ctxt->mapname=%s", ctxt->mapname);
+-
+ /* This should, but doesn't, take a const char ** */
+ err = yp_get_default_domain((char **) &ctxt->domainname);
+ if (err) {
+@@ -133,8 +133,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ memcpy(name, ctxt->mapname, len);
+ name[len] = '\0';
+ free(ctxt);
+- debug(LOGOPT_NONE, MODPREFIX "map %s: %s", name,
+- yperr_string(err));
++ logerr(MODPREFIX "map %s: %s", name, yperr_string(err));
+ return 1;
+ }
+
+@@ -146,7 +145,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1);
+ if (!ctxt->parse) {
+ free(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "failed to open parse context");
++ logmsg(MODPREFIX "failed to open parse context");
+ return 1;
+ }
+ *context = ctxt;
+@@ -161,6 +160,7 @@ int yp_all_master_callback(int status, char *ypkey, int ypkeylen,
+ (struct callback_master_data *) ypcb_data;
+ unsigned int timeout = cbdata->timeout;
+ unsigned int logging = cbdata->logging;
++ unsigned int logopt = cbdata->logopt;
+ time_t age = cbdata->age;
+ char *buffer;
+ unsigned int len;
+@@ -182,7 +182,7 @@ int yp_all_master_callback(int status, char *ypkey, int ypkeylen,
+
+ buffer = alloca(len);
+ if (!buffer) {
+- error(LOGOPT_ANY, MODPREFIX "could not malloc parse buffer");
++ error(logopt, MODPREFIX "could not malloc parse buffer");
+ return 0;
+ }
+ memset(buffer, 0, len);
+@@ -201,6 +201,8 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ struct ypall_callback ypcb;
+ struct callback_master_data ypcb_data;
++ unsigned int logging = master->default_logging;
++ unsigned int logopt = master->logopt;
+ char *mapname;
+ int err;
+
+@@ -211,7 +213,8 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ strcpy(mapname, ctxt->mapname);
+
+ ypcb_data.timeout = master->default_timeout;
+- ypcb_data.logging = master->default_logging;
++ ypcb_data.logging = logging;
++ ypcb_data.logopt = logopt;
+ ypcb_data.age = age;
+
+ ypcb.foreach = yp_all_master_callback;
+@@ -232,7 +235,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ if (err == YPERR_SUCCESS)
+ return NSS_STATUS_SUCCESS;
+
+- warn(LOGOPT_ANY,
++ info(logopt,
+ MODPREFIX "read of master map %s failed: %s",
+ mapname, yperr_string(err));
+
+@@ -249,6 +252,7 @@ int yp_all_callback(int status, char *ypkey, int ypkeylen,
+ struct autofs_point *ap = cbdata->ap;
+ struct map_source *source = cbdata->source;
+ struct mapent_cache *mc = source->mc;
++ unsigned int logopt = cbdata->logopt;
+ time_t age = cbdata->age;
+ char *key, *mapent;
+ int ret;
+@@ -264,8 +268,10 @@ int yp_all_callback(int status, char *ypkey, int ypkeylen,
+ return 0;
+
+ key = sanitize_path(ypkey, ypkeylen, ap->type, ap->logopt);
+- if (!key)
++ if (!key) {
++ error(logopt, MODPREFIX "invalid path %s", ypkey);
+ return 0;
++ }
+
+ mapent = alloca(vallen + 1);
+ strncpy(mapent, val, vallen);
+@@ -288,6 +294,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ struct ypall_callback ypcb;
+ struct callback_data ypcb_data;
++ unsigned int logopt = ap->logopt;
+ struct map_source *source;
+ char *mapname;
+ int err;
+@@ -298,6 +305,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+
+ ypcb_data.ap = ap;
+ ypcb_data.source = source;
++ ypcb_data.logopt = logopt;
+ ypcb_data.age = age;
+
+ ypcb.foreach = yp_all_callback;
+diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
+index c45b91b..356fb14 100644
+--- a/modules/mount_autofs.c
++++ b/modules/mount_autofs.c
+@@ -64,7 +64,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ fullpath = alloca(strlen(root) + name_len + 2);
+ if (!fullpath) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return 1;
+ }
+
+@@ -156,7 +156,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ }
+ nap = entry->ap;
+ nap->parent = ap;
+- set_mnt_logging(nap);
+
+ argc = 1;
+
+@@ -208,7 +207,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ return 1;
+ }
+
+- source->mc = cache_init(source);
++ source->mc = cache_init(entry->ap, source);
+ if (!source->mc) {
+ error(ap->logopt, MODPREFIX "failed to init source cache");
+ master_free_mapent(entry);
+diff --git a/modules/mount_bind.c b/modules/mount_bind.c
+index cb17ce4..04284f5 100644
+--- a/modules/mount_bind.c
++++ b/modules/mount_bind.c
+@@ -52,16 +52,14 @@ int mount_init(void **context)
+ if (lstat(t1_dir, &st1) == -1)
+ goto out;
+
+- err = spawn_mount(log_debug, "-n", "--bind", t1_dir, t2_dir, NULL);
++ err = spawn_mount(LOGOPT_NONE, "-n", "--bind", t1_dir, t2_dir, NULL);
+ if (err == 0 &&
+ lstat(t2_dir, &st2) == 0 &&
+ st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
+ bind_works = 1;
+ }
+
+- debug(LOGOPT_NONE, MODPREFIX "bind_works = %d", bind_works);
+-
+- spawn_umount(log_debug, "-n", t2_dir, NULL);
++ spawn_umount(LOGOPT_NONE, "-n", t2_dir, NULL);
+
+ out:
+ rmdir(t1_dir);
+@@ -91,7 +89,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ fullpath = alloca(rlen + name_len + 2);
+ if (!fullpath) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return 1;
+ }
+
+@@ -139,7 +137,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ "calling mount --bind " SLOPPY " -o %s %s %s",
+ options, what, fullpath);
+
+- err = spawn_bind_mount(log_debug,
++ err = spawn_bind_mount(ap->logopt,
+ SLOPPYOPT "-o", options, what, fullpath, NULL);
+
+ if (err) {
+diff --git a/modules/mount_changer.c b/modules/mount_changer.c
+index 6e04c7c..08d9147 100644
+--- a/modules/mount_changer.c
++++ b/modules/mount_changer.c
+@@ -66,7 +66,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ fullpath = alloca(rlen + name_len + 2);
+ if (!fullpath) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return 1;
+ }
+
+@@ -80,7 +80,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+
+ debug(ap->logopt, MODPREFIX "calling umount %s", what);
+
+- err = spawn_umount(log_debug, what, NULL);
++ err = spawn_umount(ap->logopt, what, NULL);
+ if (err) {
+ error(ap->logopt,
+ MODPREFIX
+@@ -115,18 +115,18 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s",
+ fstype, options, what, fullpath);
+
+- err = spawn_mount(log_debug, "-t", fstype,
++ err = spawn_mount(ap->logopt, "-t", fstype,
+ SLOPPYOPT "-o", options, what, fullpath, NULL);
+ } else {
+ debug(ap->logopt,
+ MODPREFIX "calling mount -t %s %s %s",
+ fstype, what, fullpath);
+
+- err = spawn_mount(log_debug, "-t", fstype, what, fullpath, NULL);
++ err = spawn_mount(ap->logopt, "-t", fstype, what, fullpath, NULL);
+ }
+
+ if (err) {
+- msg(MODPREFIX "failed to mount %s (type %s) on %s",
++ info(ap->logopt, MODPREFIX "failed to mount %s (type %s) on %s",
+ what, fstype, fullpath);
+
+ if (ap->type != LKP_INDIRECT)
+@@ -137,7 +137,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+
+ return 1;
+ } else {
+- msg(MODPREFIX "mounted %s type %s on %s",
++ info(ap->logopt, MODPREFIX "mounted %s type %s on %s",
+ what, fstype, fullpath);
+ return 0;
+ }
+@@ -161,7 +161,7 @@ int swapCD(const char *device, const char *slotName)
+ /* open device */
+ fd = open(device, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+- error(LOGOPT_ANY, MODPREFIX "Opening device %s failed : %s",
++ logerr(MODPREFIX "Opening device %s failed : %s",
+ device, strerror(errno));
+ return 1;
+ }
+@@ -174,7 +174,7 @@ int swapCD(const char *device, const char *slotName)
+ /* Check CD player status */
+ total_slots_available = ioctl(fd, CDROM_CHANGER_NSLOTS);
+ if (total_slots_available <= 1) {
+- error(LOGOPT_ANY, MODPREFIX
++ logerr(MODPREFIX
+ "Device %s is not an ATAPI compliant CD changer.",
+ device);
+ return 1;
+@@ -183,14 +183,14 @@ int swapCD(const char *device, const char *slotName)
+ /* load */
+ slot = ioctl(fd, CDROM_SELECT_DISC, slot);
+ if (slot < 0) {
+- error(LOGOPT_ANY, MODPREFIX "CDROM_SELECT_DISC failed");
++ logerr(MODPREFIX "CDROM_SELECT_DISC failed");
+ return 1;
+ }
+
+ /* close device */
+ status = close(fd);
+ if (status != 0) {
+- error(LOGOPT_ANY, MODPREFIX "close failed for `%s': %s",
++ logerr(MODPREFIX "close failed for `%s': %s",
+ device, strerror(errno));
+ return 1;
+ }
+diff --git a/modules/mount_ext2.c b/modules/mount_ext2.c
+index 45f0615..8cf9937 100644
+--- a/modules/mount_ext2.c
++++ b/modules/mount_ext2.c
+@@ -58,7 +58,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ fullpath = alloca(rlen + name_len + 2);
+ if (!fullpath) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return 1;
+ }
+
+@@ -108,11 +108,11 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ if (ro) {
+ debug(ap->logopt,
+ MODPREFIX "calling %s -n %s", fsck_prog, what);
+- err = spawnl(log_debug, fsck_prog, fsck_prog, "-n", what, NULL);
++ err = spawnl(ap->logopt, fsck_prog, fsck_prog, "-n", what, NULL);
+ } else {
+ debug(ap->logopt,
+ MODPREFIX "calling %s -p %s", fsck_prog, what);
+- err = spawnl(log_debug, fsck_prog, fsck_prog, "-p", what, NULL);
++ err = spawnl(ap->logopt, fsck_prog, fsck_prog, "-p", what, NULL);
+ }
+
+ /*
+@@ -132,17 +132,17 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ debug(ap->logopt,
+ MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s",
+ fstype, options, what, fullpath);
+- err = spawn_mount(log_debug, "-t", fstype,
++ err = spawn_mount(ap->logopt, "-t", fstype,
+ SLOPPYOPT "-o", options, what, fullpath, NULL);
+ } else {
+ debug(ap->logopt,
+ MODPREFIX "calling mount -t %s %s %s",
+ fstype, what, fullpath);
+- err = spawn_mount(log_debug, "-t", fstype, what, fullpath, NULL);
++ err = spawn_mount(ap->logopt, "-t", fstype, what, fullpath, NULL);
+ }
+
+ if (err) {
+- msg(MODPREFIX "failed to mount %s (type %s) on %s",
++ info(ap->logopt, MODPREFIX "failed to mount %s (type %s) on %s",
+ what, fstype, fullpath);
+
+ if (ap->type != LKP_INDIRECT)
+@@ -153,7 +153,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+
+ return 1;
+ } else {
+- debug(ap->logopt,
++ info(ap->logopt,
+ MODPREFIX "mounted %s type %s on %s",
+ what, fstype, fullpath);
+ return 0;
+diff --git a/modules/mount_generic.c b/modules/mount_generic.c
+index 1f43baa..85b4391 100644
+--- a/modules/mount_generic.c
++++ b/modules/mount_generic.c
+@@ -57,7 +57,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ fullpath = alloca(rlen + name_len + 2);
+ if (!fullpath) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return 1;
+ }
+
+@@ -93,16 +93,16 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s",
+ fstype, options, what, fullpath);
+
+- err = spawn_mount(log_debug, "-t", fstype,
++ err = spawn_mount(ap->logopt, "-t", fstype,
+ SLOPPYOPT "-o", options, what, fullpath, NULL);
+ } else {
+ debug(ap->logopt, MODPREFIX "calling mount -t %s %s %s",
+ fstype, what, fullpath);
+- err = spawn_mount(log_debug, "-t", fstype, what, fullpath, NULL);
++ err = spawn_mount(ap->logopt, "-t", fstype, what, fullpath, NULL);
+ }
+
+ if (err) {
+- msg(MODPREFIX "failed to mount %s (type %s) on %s",
++ info(ap->logopt, MODPREFIX "failed to mount %s (type %s) on %s",
+ what, fstype, fullpath);
+
+ if (ap->type != LKP_INDIRECT)
+@@ -113,7 +113,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+
+ return 1;
+ } else {
+- msg(MODPREFIX "mounted %s type %s on %s",
++ info(ap->logopt, MODPREFIX "mounted %s type %s on %s",
+ what, fstype, fullpath);
+ return 0;
+ }
+diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
+index e4480c5..bad21fc 100644
+--- a/modules/mount_nfs.c
++++ b/modules/mount_nfs.c
+@@ -133,14 +133,14 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ else
+ vers = NFS_VERS_MASK | NFS_PROTO_MASK;
+
+- if (!parse_location(&hosts, what)) {
+- warn(ap->logopt, MODPREFIX "no hosts available");
++ if (!parse_location(ap->logopt, &hosts, what)) {
++ info(ap->logopt, MODPREFIX "no hosts available");
+ return 1;
+ }
+- prune_host_list(&hosts, vers, nfsoptions, ap->random_selection);
++ prune_host_list(ap->logopt, &hosts, vers, nfsoptions, ap->random_selection);
+
+ if (!hosts) {
+- warn(ap->logopt, MODPREFIX "no hosts available");
++ info(ap->logopt, MODPREFIX "no hosts available");
+ return 1;
+ }
+
+@@ -159,7 +159,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ fullpath = alloca(rlen + name_len + 2);
+ if (!fullpath) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ free_host_list(&hosts);
+ return 1;
+ }
+@@ -252,19 +252,19 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ MODPREFIX "calling mount -t %s " SLOPPY
+ "-o %s %s %s", fstype, nfsoptions, loc, fullpath);
+
+- err = spawn_mount(log_debug,
++ err = spawn_mount(ap->logopt,
+ "-t", fstype, SLOPPYOPT "-o",
+ nfsoptions, loc, fullpath, NULL);
+ } else {
+ debug(ap->logopt,
+ MODPREFIX "calling mount -t %s %s %s",
+ fstype, loc, fullpath);
+- err = spawn_mount(log_debug,
++ err = spawn_mount(ap->logopt,
+ "-t", fstype, loc, fullpath, NULL);
+ }
+
+ if (!err) {
+- msg(MODPREFIX "mounted %s on %s", loc, fullpath);
++ info(ap->logopt, MODPREFIX "mounted %s on %s", loc, fullpath);
+ free(loc);
+ free_host_list(&hosts);
+ ap->ghost = save_ghost;
+@@ -280,7 +280,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+
+ /* If we get here we've failed to complete the mount */
+
+- msg(MODPREFIX "nfs: mount failure %s on %s", what, fullpath);
++ info(ap->logopt, MODPREFIX "nfs: mount failure %s on %s", what, fullpath);
+
+ if (ap->type != LKP_INDIRECT)
+ return 1;
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 079bda6..186e567 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -277,7 +277,7 @@ int parse_init(int argc, const char *const *argv, void **context)
+
+ if (!(ctxt = (struct parse_context *) malloc(sizeof(struct parse_context)))) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ *context = NULL;
+ return 1;
+ }
+@@ -302,7 +302,7 @@ int parse_init(int argc, const char *const *argv, void **context)
+
+ if (!def) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, MODPREFIX "strdup: %s", estr);
++ logerr(MODPREFIX "strdup: %s", estr);
+ break;
+ }
+
+@@ -387,7 +387,7 @@ int parse_init(int argc, const char *const *argv, void **context)
+ if (!noptstr) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ kill_context(ctxt);
+- crit(LOGOPT_ANY, MODPREFIX "%s", estr);
++ logerr(MODPREFIX "%s", estr);
+ *context = NULL;
+ return 1;
+ }
+@@ -408,7 +408,7 @@ int parse_init(int argc, const char *const *argv, void **context)
+ char *tmp = concat_options(gbl_options, ctxt->optstr);
+ if (!tmp) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, MODPREFIX "concat_options: %s", estr);
++ logerr(MODPREFIX "concat_options: %s", estr);
+ free(gbl_options);
+ } else
+ ctxt->optstr = tmp;
+@@ -472,7 +472,7 @@ static char *concat_options(char *left, char *right)
+
+ if (ret == NULL) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, MODPREFIX "malloc: %s", estr);
++ logerr(MODPREFIX "malloc: %s", estr);
+ return NULL;
+ }
+
+@@ -637,8 +637,7 @@ static int check_is_multi(const char *mapent)
+ int not_first_chunk = 0;
+
+ if (!p) {
+- crit(LOGOPT_ANY,
+- MODPREFIX "unexpected NULL map entry pointer");
++ logerr(MODPREFIX "unexpected NULL map entry pointer");
+ return 0;
+ }
+
+@@ -1021,7 +1020,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ pmapent = alloca(mapent_len + 1);
+ if (!pmapent) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ ctxt->subst = removestdenv(ctxt->subst);
+ macro_unlock();
+ pthread_setcancelstate(cur_state, NULL);
+@@ -1041,7 +1040,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ options = strdup(ctxt->optstr ? ctxt->optstr : "");
+ if (!options) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "strdup: %s", estr);
++ logerr(MODPREFIX "strdup: %s", estr);
+ return 1;
+ }
+ optlen = strlen(options);
+@@ -1119,7 +1118,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ if (!m_root) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ free(options);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return 1;
+ }
+ strcpy(m_root, name);
+@@ -1129,7 +1128,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ if (!m_root) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ free(options);
+- error(ap->logopt, MODPREFIX "alloca: %s", estr);
++ logerr(MODPREFIX "alloca: %s", estr);
+ return 1;
+ }
+ strcpy(m_root, ap->path);
+diff --git a/modules/replicated.c b/modules/replicated.c
+index e15587c..14b20a9 100644
+--- a/modules/replicated.c
++++ b/modules/replicated.c
+@@ -113,7 +113,7 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "socket creation failed: %s", estr);
++ logerr("socket creation failed: %s", estr);
+ return PROXIMITY_ERROR;
+ }
+
+@@ -127,7 +127,7 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
+ ret = ioctl(sock, SIOCGIFCONF, &ifc);
+ if (ret == -1) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "ioctl: %s", estr);
++ logerr("ioctl: %s", estr);
+ close(sock);
+ return PROXIMITY_ERROR;
+ }
+@@ -176,7 +176,7 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
+ ret = ioctl(sock, SIOCGIFNETMASK, &nmptr);
+ if (ret == -1) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "ioctl: %s", estr);
++ logerr("ioctl: %s", estr);
+ close(sock);
+ return PROXIMITY_ERROR;
+ }
+@@ -387,7 +387,7 @@ static unsigned short get_port_option(const char *options)
+ return (unsigned short) port;
+ }
+
+-static unsigned int get_nfs_info(struct host *host,
++static unsigned int get_nfs_info(unsigned logopt, struct host *host,
+ struct conn_info *pm_info, struct conn_info *rpc_info,
+ const char *proto, unsigned int version,
+ const char *options, unsigned int random_selection)
+@@ -533,7 +533,7 @@ done_ver:
+ return supported;
+ }
+
+-static int get_vers_and_cost(struct host *host,
++static int get_vers_and_cost(unsigned logopt, struct host *host,
+ unsigned int version, const char *options,
+ unsigned int random_selection)
+ {
+@@ -559,7 +559,7 @@ static int get_vers_and_cost(struct host *host,
+ vers &= version;
+
+ if (version & UDP_REQUESTED) {
+- supported = get_nfs_info(host,
++ supported = get_nfs_info(logopt, host,
+ &pm_info, &rpc_info, "udp", vers,
+ options, random_selection);
+ if (supported) {
+@@ -569,7 +569,7 @@ static int get_vers_and_cost(struct host *host,
+ }
+
+ if (version & TCP_REQUESTED) {
+- supported = get_nfs_info(host,
++ supported = get_nfs_info(logopt, host,
+ &pm_info, &rpc_info, "tcp", vers,
+ options, random_selection);
+ if (supported) {
+@@ -581,7 +581,7 @@ static int get_vers_and_cost(struct host *host,
+ return ret;
+ }
+
+-static int get_supported_ver_and_cost(struct host *host,
++static int get_supported_ver_and_cost(unsigned logopt, struct host *host,
+ unsigned int version, const char *options,
+ unsigned int random_selection)
+ {
+@@ -636,7 +636,7 @@ static int get_supported_ver_and_cost(struct host *host,
+ vers = NFS4_VERSION;
+ break;
+ default:
+- crit(LOGOPT_ANY, "called with invalid version: 0x%x\n", version);
++ crit(logopt, "called with invalid version: 0x%x\n", version);
+ return 0;
+ }
+
+@@ -701,7 +701,7 @@ done:
+ return 0;
+ }
+
+-int prune_host_list(struct host **list,
++int prune_host_list(unsigned logopt, struct host **list,
+ unsigned int vers, const char *options,
+ unsigned int random_selection)
+ {
+@@ -742,7 +742,7 @@ int prune_host_list(struct host **list,
+ break;
+
+ if (this->name) {
+- status = get_vers_and_cost(this, vers,
++ status = get_vers_and_cost(logopt, this, vers,
+ options, random_selection);
+ if (!status) {
+ if (this == first) {
+@@ -833,7 +833,7 @@ int prune_host_list(struct host **list,
+ remove_host(list, this);
+ add_host(&new, this);
+ } else {
+- status = get_supported_ver_and_cost(this,
++ status = get_supported_ver_and_cost(logopt, this,
+ selected_version, options,
+ random_selection);
+ if (status) {
+@@ -886,11 +886,9 @@ static int add_host_addrs(struct host **list, const char *host, unsigned int wei
+ buf, MAX_IFC_BUF, &result, &ghn_errno);
+ if (ret || !result) {
+ if (ghn_errno == -1)
+- error(LOGOPT_ANY,
+- "host %s: lookup failure %d", host, errno);
++ logmsg("host %s: lookup failure %d", host, errno);
+ else
+- error(LOGOPT_ANY,
+- "host %s: lookup failure %d", host, ghn_errno);
++ logmsg("host %s: lookup failure %d", host, ghn_errno);
+ return 0;
+ }
+
+@@ -965,7 +963,7 @@ static int add_local_path(struct host **hosts, const char *path)
+ return 1;
+ }
+
+-int parse_location(struct host **hosts, const char *list)
++int parse_location(unsigned logopt, struct host **hosts, const char *list)
+ {
+ char *str, *p, *delim;
+ unsigned int empty = 1;
+@@ -1072,8 +1070,7 @@ void dump_host_list(struct host *hosts)
+
+ this = hosts;
+ while (this) {
+- debug(LOGOPT_ANY,
+- "name %s path %s version %x proximity %u weight %u cost %u",
++ logmsg("name %s path %s version %x proximity %u weight %u cost %u",
+ this->name, this->path, this->version,
+ this->proximity, this->weight, this->cost);
+ this = this->next;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 85af0ad..fcfbe62 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -50,6 +50,7 @@
+ - fix off-by-one error for lookup of map keys exactly 255 characters long.
+ - improve handling of server not available.
+ - fix LDAP_URI server selection.
++- add authentication option for using an external credential cache.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
+index 5b5c475..d6a754d 100644
+--- a/include/lookup_ldap.h
++++ b/include/lookup_ldap.h
+@@ -67,10 +67,10 @@ struct lookup_context {
+ char *user;
+ char *secret;
+ char *client_princ;
++ char *client_cc;
+ int kinit_done;
+ int kinit_successful;
+ #ifdef WITH_SASL
+- krb5_principal krb5_client_princ;
+ krb5_context krb5ctxt;
+ krb5_ccache krb5_ccache;
+ sasl_conn_t *sasl_conn;
+diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
+index 303b7f2..f24f46b 100644
+--- a/modules/cyrus-sasl.c
++++ b/modules/cyrus-sasl.c
+@@ -72,6 +72,7 @@
+ */
+ static const char *krb5ccenv = "KRB5CCNAME";
+ static const char *krb5ccval = "MEMORY:_autofstkt";
++static const char *default_client = "autofsclient";
+ static pthread_mutex_t krb5cc_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static unsigned int krb5cc_in_use = 0;
+
+@@ -376,7 +377,7 @@ int
+ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ {
+ krb5_error_code ret;
+- krb5_principal tgs_princ, krb5_client_princ = ctxt->krb5_client_princ;
++ krb5_principal tgs_princ, krb5_client_princ;
+ krb5_creds my_creds;
+ char *tgs_name;
+ int status;
+@@ -386,8 +387,8 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ ctxt->kinit_done = 1;
+
+ debug(logopt,
+- "initializing kerberos ticket: client principal %s ",
+- ctxt->client_princ ? ctxt->client_princ : "autofsclient");
++ "initializing kerberos ticket: client principal %s",
++ ctxt->client_princ ? ctxt->client_princ : default_client);
+
+ ret = krb5_init_context(&ctxt->krb5ctxt);
+ if (ret) {
+@@ -424,13 +425,12 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ "calling krb5_sname_to_principal using defaults");
+
+ ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
+- "autofsclient", KRB5_NT_SRV_HST,
++ default_client, KRB5_NT_SRV_HST,
+ &krb5_client_princ);
+ if (ret) {
+ error(logopt,
+ "krb5_sname_to_principal failed for "
+- "%s with error %d",
+- ctxt->client_princ ? "" : "autofsclient", ret);
++ "%s with error %d", default_client, ret);
+ goto out_cleanup_cc;
+ }
+
+@@ -441,11 +441,11 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ debug(logopt,
+ "krb5_unparse_name failed with error %d",
+ ret);
+- goto out_cleanup_cc;
++ goto out_cleanup_client_princ;
+ }
+
+ debug(logopt,
+- "principal used for authentication: \"%s\"", tmp_name);
++ "principal used for authentication: %s", tmp_name);
+
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tmp_name);
+ }
+@@ -461,14 +461,14 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ if (ret) {
+ error(logopt,
+ "krb5_build_principal failed with error %d", ret);
+- goto out_cleanup_cc;
++ goto out_cleanup_client_princ;
+ }
+
+ ret = krb5_unparse_name(ctxt->krb5ctxt, tgs_princ, &tgs_name);
+ if (ret) {
+ error(logopt, "krb5_unparse_name failed with error %d",
+ ret);
+- goto out_cleanup_cc;
++ goto out_cleanup_client_princ;
+ }
+
+ debug(logopt, "Using tgs name %s", tgs_name);
+@@ -486,7 +486,6 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ goto out_cleanup_unparse;
+ }
+
+-
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+@@ -503,7 +502,7 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ if (ret) {
+ error(logopt,
+ "krb5_cc_initialize failed with error %d", ret);
+- goto out_cleanup_unparse;
++ goto out_cleanup_creds;
+ }
+
+ /* and store credentials for that principal */
+@@ -511,26 +510,34 @@ sasl_do_kinit(unsigned logopt, struct lookup_context *ctxt)
+ if (ret) {
+ error(logopt,
+ "krb5_cc_store_cred failed with error %d", ret);
+- goto out_cleanup_unparse;
++ goto out_cleanup_creds;
+ }
+
+ /* finally, set the environment variable to point to our
+ * credentials cache */
+ if (setenv(krb5ccenv, krb5ccval, 1) != 0) {
+ error(logopt, "setenv failed with %d", errno);
+- goto out_cleanup_unparse;
++ goto out_cleanup_creds;
+ }
+ ctxt->kinit_successful = 1;
+
+ debug(logopt, "Kerberos authentication was successful!");
+
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
++ krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
++ krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
++ krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
+
+ return 0;
+
+-out_cleanup_unparse:
++out_cleanup_creds:
+ krb5cc_in_use--;
++ krb5_free_cred_contents(ctxt->krb5ctxt, &my_creds);
++out_cleanup_unparse:
++ krb5_free_principal(ctxt->krb5ctxt, tgs_princ);
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
++out_cleanup_client_princ:
++ krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
+ out_cleanup_cc:
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+@@ -554,6 +561,152 @@ out_cleanup_cc:
+ }
+
+ /*
++ * Check a client given external credential cache.
++ *
++ * Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful
++ * are set for cleanup purposes. The krb5 context and ccache entries in
++ * the lookup_context are also filled in.
++ *
++ * Upon failure, -1 is returned.
++ */
++int
++sasl_do_kinit_ext_cc(unsigned logopt, struct lookup_context *ctxt)
++{
++ krb5_principal def_princ;
++ krb5_principal krb5_client_princ;
++ krb5_error_code ret;
++ char *cc_princ, *client_princ;
++
++ if (ctxt->kinit_done)
++ return 0;
++ ctxt->kinit_done = 1;
++
++ debug(logopt,
++ "using external credential cache for auth: client principal %s",
++ ctxt->client_princ ? ctxt->client_princ : default_client);
++
++ ret = krb5_init_context(&ctxt->krb5ctxt);
++ if (ret) {
++ error(logopt, "krb5_init_context failed with %d", ret);
++ return -1;
++ }
++
++ ret = krb5_cc_resolve(ctxt->krb5ctxt, ctxt->client_cc, &ctxt->krb5_ccache);
++ if (ret) {
++ error(logopt, "krb5_cc_resolve failed with error %d",
++ ret);
++ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
++ krb5_free_context(ctxt->krb5ctxt);
++ return -1;
++ }
++
++ ret = krb5_cc_get_principal(ctxt->krb5ctxt, ctxt->krb5_ccache, &def_princ);
++ if (ret) {
++ error(logopt, "krb5_cc_get_principal failed with error %d", ret);
++ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
++ krb5_free_context(ctxt->krb5ctxt);
++ return -1;
++ }
++
++ ret = krb5_unparse_name(ctxt->krb5ctxt, def_princ, &cc_princ);
++ if (ret) {
++ error(logopt, "krb5_unparse_name failed with error %d", ret);
++ krb5_free_principal(ctxt->krb5ctxt, def_princ);
++ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
++ krb5_free_context(ctxt->krb5ctxt);
++ return -1;
++ }
++
++ debug(logopt, "external credential cache default principal %s", cc_princ);
++
++ /*
++ * If the principal isn't set in the config construct the default
++ * so we can check against the default principal of the external
++ * cred cache.
++ */
++ if (ctxt->client_princ)
++ client_princ = ctxt->client_princ;
++ else {
++ debug(logopt,
++ "calling krb5_sname_to_principal using defaults");
++
++ ret = krb5_sname_to_principal(ctxt->krb5ctxt, NULL,
++ default_client, KRB5_NT_SRV_HST,
++ &krb5_client_princ);
++ if (ret) {
++ error(logopt,
++ "krb5_sname_to_principal failed for "
++ "%s with error %d", default_client, ret);
++ krb5_free_principal(ctxt->krb5ctxt, def_princ);
++ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
++ krb5_free_context(ctxt->krb5ctxt);
++ return -1;
++ }
++
++
++ ret = krb5_unparse_name(ctxt->krb5ctxt,
++ krb5_client_princ, &client_princ);
++ if (ret) {
++ debug(logopt,
++ "krb5_unparse_name failed with error %d",
++ ret);
++ krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
++ krb5_free_principal(ctxt->krb5ctxt, def_princ);
++ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
++ krb5_free_context(ctxt->krb5ctxt);
++ return -1;
++ }
++
++ debug(logopt,
++ "principal used for authentication: %s", client_princ);
++
++ krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
++ }
++
++ /*
++ * Check if the principal to be used matches the default principal in
++ * the external cred cache.
++ */
++ if (strcmp(cc_princ, client_princ)) {
++ error(logopt,
++ "configured client principal %s ",
++ ctxt->client_princ);
++ error(logopt,
++ "external credential cache default principal %s",
++ cc_princ);
++ error(logopt,
++ "cannot use credential cache, external "
++ "default principal does not match configured "
++ "principal");
++ if (!ctxt->client_princ)
++ krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
++ krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
++ krb5_free_principal(ctxt->krb5ctxt, def_princ);
++ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
++ krb5_free_context(ctxt->krb5ctxt);
++ return -1;
++ }
++
++ if (!ctxt->client_princ)
++ krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
++ krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
++ krb5_free_principal(ctxt->krb5ctxt, def_princ);
++
++ /* Set the environment variable to point to the external cred cache */
++ if (setenv(krb5ccenv, ctxt->client_cc, 1) != 0) {
++ error(logopt, "setenv failed with %d", errno);
++ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
++ krb5_free_context(ctxt->krb5ctxt);
++ return -1;
++ }
++ ctxt->kinit_successful = 1;
++
++ debug(logopt, "Kerberos authentication was successful!");
++
++ return 0;
++}
++
++/*
+ * Attempt to bind to the ldap server using a given authentication
+ * mechanism. ldap should be a properly initialzed ldap pointer.
+ *
+@@ -570,7 +723,11 @@ sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const c
+ int result;
+
+ if (!strncmp(mech, "GSSAPI", 6)) {
+- if (sasl_do_kinit(logopt, ctxt) != 0)
++ if (ctxt->client_cc)
++ result = sasl_do_kinit_ext_cc(logopt, ctxt);
++ else
++ result = sasl_do_kinit(logopt, ctxt);
++ if (result != 0)
+ return NULL;
+ }
+
+@@ -774,7 +931,7 @@ autofs_sasl_done(struct lookup_context *ctxt)
+ if (status)
+ fatal(status);
+
+- if (--krb5cc_in_use)
++ if (--krb5cc_in_use || ctxt->client_cc)
+ ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ else
+ ret = krb5_cc_destroy(ctxt->krb5ctxt, ctxt->krb5_ccache);
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 93f0477..13fbff7 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -651,7 +651,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
+ xmlNodePtr root = NULL;
+ char *authrequired, *auth_conf, *authtype;
+ char *user = NULL, *secret = NULL;
+- char *client_princ = NULL;
++ char *client_princ = NULL, *client_cc = NULL;
+ char *usetls, *tlsrequired;
+
+ authtype = user = secret = NULL;
+@@ -840,6 +840,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
+ * client. The default is "autofsclient/hostname@REALM".
+ */
+ (void)get_property(logopt, root, "clientprinc", &client_princ);
++ (void)get_property(logopt, root, "credentialcache", &client_cc);
+
+ ctxt->auth_conf = auth_conf;
+ ctxt->use_tls = use_tls;
+@@ -851,6 +852,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
+ ctxt->user = user;
+ ctxt->secret = secret;
+ ctxt->client_princ = client_princ;
++ ctxt->client_cc = client_cc;
+
+ debug(logopt, MODPREFIX
+ "ldap authentication configured with the following options:");
+@@ -863,9 +865,10 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt)
+ debug(logopt, MODPREFIX
+ "user: %s, "
+ "secret: %s, "
+- "client principal: %s",
++ "client principal: %s "
++ "credential cache: %s",
+ user, secret ? "specified" : "unspecified",
+- client_princ);
++ client_princ, client_cc);
+
+ out:
+ xmlFreeDoc(doc);
+@@ -1128,6 +1131,8 @@ static void free_context(struct lookup_context *ctxt)
+ free(ctxt->secret);
+ if (ctxt->client_princ)
+ free(ctxt->client_princ);
++ if (ctxt->client_cc)
++ free(ctxt->client_cc);
+ if (ctxt->mapname)
+ free(ctxt->mapname);
+ if (ctxt->qdn)
+diff --git a/samples/autofs_ldap_auth.conf b/samples/autofs_ldap_auth.conf
+index e10d1ea..a1f60c0 100644
+--- a/samples/autofs_ldap_auth.conf
++++ b/samples/autofs_ldap_auth.conf
+@@ -56,6 +56,11 @@ clientprinc - When using GSSAPI authentication, this attribute is
+ consulted to determine the principal name to use when
+ authenticating to the directory server. By default, this will
+ be set to "autofsclient/<fqdn>@<REALM>.
++
++credentialcache - When using GSSAPI authentication, this attribute
++ can be used to specify an externally configured credential
++ cache that is used during authentication. By default, autofs
++ will setup a memory based credential cache.
+ -->
+
+ <autofs_ldap_sasl_conf
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 1bf4b27..678e764 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -10,6 +10,7 @@
+ - add quoting for exports gathered by hosts map.
+ - fix wait time resolution in alarm and state queue handlers.
+ - fix handling of quoted slash alone.
++- fix parse confusion between attribute and attribute value.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 9bfeefa..ff69a24 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -272,7 +272,7 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ return DNSERVER;
+ }
+
+- {DNATTRSTR} {
++ {DNATTRSTR}/"=" {
+ strcpy(master_lval.strtype, master_text);
+ return DNATTR;
+ }
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 98d082c..20562bd 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -13,6 +13,7 @@
+ - fix parse confusion between attribute and attribute value.
+ - fix version passed to get_supported_ver_and_cost.
+ - mark map instances stale so they aren't "cleaned" during updates.
++- fix large file compile time option.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/Makefile.rules b/Makefile.rules
+index b1d1a49..30716dc 100644
+--- a/Makefile.rules
++++ b/Makefile.rules
+@@ -44,7 +44,7 @@ CXXFLAGS = $(CFLAGS)
+ LD = ld
+ SOLDFLAGS = -shared
+
+-CFLAGS += -D_REENTRANT
++CFLAGS += -D_REENTRANT -D_FILE_OFFSET_BITS=64
+ LDFLAGS += -lpthread
+
+ ifdef DMALLOCLIB
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index c6ab15f..5aee44c 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -16,6 +16,7 @@
+ - fix large file compile time option.
+ - don't fail on empty master map.
+ - add support for the "%" hack for case insensitive attribute schemas.
++- fix "nosymlink" option handling and add desription to man page.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index 98afaa9..69c796e 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -138,6 +138,14 @@ Treat errors when mounting file systems as fatal. This is important when
+ multiple file systems should be mounted (`multimounts'). If this option
+ is given, no file system is mounted at all if at least one file system
+ can't be mounted.
++.TP
++.I "nosymlink"
++This is an autofs specific option that is a pseudo mount option and
++so is given without a leading dash. Historically this option was used
++to prevent symlinking of local NFS mounts. Nowadays it can be used to
++prevent bind mounting of local NFS filesystems as well. If you need to
++prevent bind mounting for only specific entrys in a map then this
++can be done by adding the "port=" mount option to the given entries.
+ .SH GENERAL SYSTEM DEFAULTS CONFIGURATION
+ .P
+ The default value of several general settings may be changed in the
+diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
+index 25f72b9..e7a9a8a 100644
+--- a/modules/mount_nfs.c
++++ b/modules/mount_nfs.c
+@@ -214,7 +214,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ port_opt = strstr(nfsoptions, "port=");
+
+ /* Port option specified, don't try to bind */
+- if (!port_opt && this->proximity == PROXIMITY_LOCAL) {
++ if (!nosymlink && !port_opt && this->proximity == PROXIMITY_LOCAL) {
+ /* Local host -- do a "bind" */
+ const char *bind_options = ro ? "ro" : "";
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 678e764..aa5d1c1 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -11,6 +11,7 @@
+ - fix wait time resolution in alarm and state queue handlers.
+ - fix handling of quoted slash alone.
+ - fix parse confusion between attribute and attribute value.
++- fix version passed to get_supported_ver_and_cost.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/replicated.c b/modules/replicated.c
+index de1b40c..0764d4a 100644
+--- a/modules/replicated.c
++++ b/modules/replicated.c
+@@ -607,12 +607,31 @@ static int get_supported_ver_and_cost(struct host *host, unsigned int version, c
+
+ parms.pm_prog = NFS_PROGRAM;
+
++ /*
++ * The version passed in is the version as defined in
++ * include/replicated.h. However, the version we want to send
++ * off to the rpc calls should match the program version of NFS.
++ * So, we do the conversion here.
++ */
+ if (version & UDP_SELECTED_MASK) {
+ proto = "udp";
+- vers = (version << 8);
+- } else {
++ version >>= 8;
++ } else
+ proto = "tcp";
+- vers = version;
++
++ switch (version) {
++ case NFS2_SUPPORTED:
++ vers = NFS2_VERSION;
++ break;
++ case NFS3_SUPPORTED:
++ vers = NFS3_VERSION;
++ break;
++ case NFS4_SUPPORTED:
++ vers = NFS4_VERSION;
++ break;
++ default:
++ crit(LOGOPT_ANY, "called with invalid version: 0x%x\n", version);
++ return 0;
+ }
+
+ rpc_info.proto = getprotobyname(proto);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 9312ad5..6379d18 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -47,6 +47,7 @@
+ - fix for dynamic logging breaking non-sasl build (Guillaume Rousse)
+ - eliminate NULL proc ping for singleton host or local mounts.
+ - fix incorrect read/write size of startup status token (Matthias Koenig).
++- fix off-by-one error for lookup of map keys exactly 255 characters long.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index 23ea07d..550bf5c 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -1047,7 +1047,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ debug(ap->logopt, MODPREFIX "looking up %s", name);
+
+- key_len = snprintf(key, KEY_MAX_LEN, "%s", name);
++ key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name);
+ if (key_len > KEY_MAX_LEN)
+ return NSS_STATUS_NOTFOUND;
+
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 93a1b40..b8484a2 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -2053,7 +2053,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ debug(ap->logopt, MODPREFIX "looking up %s", name);
+
+- key_len = snprintf(key, KEY_MAX_LEN, "%s", name);
++ key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name);
+ if (key_len > KEY_MAX_LEN)
+ return NSS_STATUS_NOTFOUND;
+
+diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
+index bb1ca42..fee8b16 100644
+--- a/modules/lookup_nisplus.c
++++ b/modules/lookup_nisplus.c
+@@ -476,7 +476,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ debug(ap->logopt, MODPREFIX "looking up %s", name);
+
+- key_len = snprintf(key, KEY_MAX_LEN, "%s", name);
++ key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name);
+ if (key_len > KEY_MAX_LEN)
+ return NSS_STATUS_NOTFOUND;
+
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index e8ca8e8..5f4f95f 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -567,7 +567,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ debug(ap->logopt, MODPREFIX "looking up %s", name);
+
+- key_len = snprintf(key, KEY_MAX_LEN, "%s", name);
++ key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name);
+ if (key_len > KEY_MAX_LEN)
+ return NSS_STATUS_NOTFOUND;
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 8df22ae..2ce58b4 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -6,6 +6,7 @@
+ - add multi nsswitch lookup.
+ - change random multiple server selection option name to be consistent
+ with existing downstream version 4 naming.
++- fix mount point directory creation for bind mounts.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 294c511..9809b9c 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -104,11 +104,14 @@ static int do_mkdir(const char *parent, const char *path, mode_t mode)
+ status = statfs(parent, &fs);
+ if ((status != -1 && fs.f_type == (__SWORD_TYPE) AUTOFS_SUPER_MAGIC) ||
+ contained_in_local_fs(path)) {
+- if (mkdir(path, mode) == -1)
++ if (mkdir(path, mode) == -1) {
++ errno = EACCES;
+ return 0;
++ }
+ return 1;
+ }
+
++ errno = EACCES;
+ return 0;
+ }
+
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 179e74b..9a39a6f 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -604,6 +604,14 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+ }
+ ioctlfd = me->ioctlfd;
+ } else {
++ /* offset isn't mounted, return success and try to recover */
++ if (!is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
++ debug(ap->logopt,
++ "offset %s unexpectedly not mounted",
++ me->key);
++ return 0;
++ }
++
+ ioctlfd = open(me->key, O_RDONLY);
+ if (ioctlfd != -1) {
+ if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
+@@ -689,11 +697,19 @@ force_umount:
+ } else
+ msg("umounted offset mount %s", me->key);
+
++ if (!rv && me->dir_created) {
++ if (rmdir(me->key) == -1) {
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ warn(ap->logopt, "failed to remove dir %s: %s",
++ me->key, estr);
++ }
++ }
+ return rv;
+ }
+
+-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, int is_autofs_fs)
++int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+ {
++ char buf[MAX_ERR_BUF];
+ struct mnt_params *mp;
+ time_t timeout = ap->exp_timeout;
+ struct stat st;
+@@ -740,36 +756,38 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, int is_autof
+ return 0;
+ }
+
+- if (is_autofs_fs) {
+- /* In case the directory doesn't exist, try to mkdir it */
+- if (mkdir_path(me->key, 0555) < 0) {
+- if (errno != EEXIST) {
+- crit(ap->logopt,
+- "failed to create mount directory %s %d",
+- me->key, errno);
+- return -1;
+- }
++ /* In case the directory doesn't exist, try to mkdir it */
++ if (mkdir_path(me->key, 0555) < 0) {
++ if (errno == EEXIST) {
+ /*
+ * If we recieve an error, and it's EEXIST
+ * we know the directory was not created.
+ */
+ me->dir_created = 0;
++ } else if (errno == EACCES) {
++ /*
++ * We require the mount point directory to exist when
++ * installing multi-mount triggers into a host
++ * filesystem.
++ *
++ * If it doesn't exist it is not a valid part of the
++ * mount heirachy.
++ */
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ debug(ap->logopt,
++ "can't create mount directory: %s, %s",
++ me->key, estr);
++ return -1;
+ } else {
+- /* No errors so the directory was successfully created */
+- me->dir_created = 1;
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ crit(ap->logopt,
++ "failed to create mount directory: %s, %s",
++ me->key, estr);
++ return -1;
+ }
+ } else {
+- me->dir_created = 0;
+-
+- /*
+- * We require the mount point directory to exist when
+- * installing multi-mount triggers into a host filesystem.
+- *
+- * If it doesn't exist it is not a valid part of the
+- * mount heirachy so we silently succeed here.
+- */
+- if (stat(me->key, &st) == -1 && errno == ENOENT)
+- return 0;
++ /* No errors so the directory was successfully created */
++ me->dir_created = 1;
+ }
+
+ debug(ap->logopt,
+@@ -832,10 +850,8 @@ out_close:
+ out_umount:
+ umount(me->key);
+ out_err:
+- if (is_autofs_fs) {
+- if (stat(me->key, &st) == 0 && me->dir_created)
+- rmdir_path(ap, me->key, st.st_dev);
+- }
++ if (stat(me->key, &st) == 0 && me->dir_created)
++ rmdir_path(ap, me->key, st.st_dev);
+
+ return -1;
+ }
+diff --git a/include/automount.h b/include/automount.h
+index 106ed0a..d9e4ecd 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -470,7 +470,7 @@ void *expire_proc_direct(void *);
+ int expire_offsets_direct(struct autofs_point *ap, struct mapent *me, int now);
+ int mount_autofs_indirect(struct autofs_point *ap);
+ int mount_autofs_direct(struct autofs_point *ap);
+-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, int is_autofs_fs);
++int mount_autofs_offset(struct autofs_point *ap, struct mapent *me);
+ void submount_signal_parent(struct autofs_point *ap, unsigned int success);
+ int umount_autofs(struct autofs_point *ap, int force);
+ int umount_autofs_indirect(struct autofs_point *ap);
+diff --git a/lib/parse_subs.c b/lib/parse_subs.c
+index 0c45905..ad19f34 100644
+--- a/lib/parse_subs.c
++++ b/lib/parse_subs.c
+@@ -388,10 +388,8 @@ int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me,
+ struct mapent *oe;
+ struct list_head *pos = NULL;
+ unsigned int fs_path_len;
+- struct statfs fs;
+- struct stat st;
+- unsigned int mounted, is_autofs_fs;
+- int ret, start;
++ unsigned int mounted;
++ int start;
+
+ fs_path_len = strlen(root) + strlen(base);
+ if (fs_path_len > PATH_MAX)
+@@ -399,15 +397,6 @@ int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me,
+
+ strcpy(path, root);
+ strcat(path, base);
+- ret = statfs(path, &fs);
+- if (ret == -1) {
+- /* There's no mount yet - it must be autofs */
+- if (errno == ENOENT)
+- is_autofs_fs = 1;
+- else
+- return -1;
+- } else
+- is_autofs_fs = fs.f_type == (__SWORD_TYPE) AUTOFS_SUPER_MAGIC ? 1 : 0;
+
+ mounted = 0;
+ start = strlen(root);
+@@ -424,20 +413,9 @@ int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me,
+ if (!oe)
+ goto cont;
+
+- /*
+- * If the host filesystem is not an autofs fs
+- * we require the mount point directory exist
+- * and that permissions are OK.
+- */
+- if (!is_autofs_fs) {
+- ret = stat(oe->key, &st);
+- if (ret == -1)
+- goto cont;
+- }
+-
+ debug(ap->logopt, "mount offset %s", oe->key);
+
+- if (mount_autofs_offset(ap, oe, is_autofs_fs) < 0)
++ if (mount_autofs_offset(ap, oe) < 0)
+ warn(ap->logopt, "failed to mount offset");
+ else
+ mounted++;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index a7ac9fb..93c79cf 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -36,6 +36,7 @@
+ - fix map entry expansion when undefined macro is present.
+ - remove unused export validation code.
+ - add dynamic logging (adapted from v4 patch from Jeff Moyer).
++- fix recursive loopback mounts (Matthias Koenig).
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/spawn.c b/daemon/spawn.c
+index 3d5ea56..ab3274c 100644
+--- a/daemon/spawn.c
++++ b/daemon/spawn.c
+@@ -290,7 +290,16 @@ int spawn_mount(unsigned logopt, ...)
+
+ va_start(arg, logopt);
+ p = argv + 1;
+- while ((*p++ = va_arg(arg, char *)));
++ while ((*p = va_arg(arg, char *))) {
++ if (options == SPAWN_OPT_NONE && !strcmp(*p, "-o")) {
++ *(++p) = va_arg(arg, char *);
++ if (!*p)
++ break;
++ if (strstr(*p, "loop"))
++ options = SPAWN_OPT_ACCESS;
++ }
++ p++;
++ }
+ va_end(arg);
+
+ while (retries--) {
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 933b1a1..0340940 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -28,6 +28,7 @@
+ - work around segv at exit due to libxml2 tsd usage.
+ - re-read config on HUP signal.
+ - add LDAP_URI, LDAP_TIMEOUT and LDAP_NETWORK_TIMEOUT configuration options.
++- fix forground logging and add option to man page.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 58f1901..51f6a8b 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -58,14 +58,13 @@ unsigned int global_random_selection; /* use random policy when selecting
+ static int start_pipefd[2];
+ static int st_stat = 0;
+ static int *pst_stat = &st_stat;
++static pthread_t state_mach_thid;
+
+ /* Pre-calculated kernel packet length */
+ static size_t kpkt_len;
+
+ /* Attribute to create detached thread */
+ pthread_attr_t thread_attr;
+-/* Attribute to create normal thread */
+-pthread_attr_t thread_attr_nodetach;
+
+ struct master_readmap_cond mrc = {
+ PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, NULL, 0, 0, 0, 0};
+@@ -75,9 +74,6 @@ struct startup_cond suc = {
+
+ pthread_key_t key_thread_stdenv_vars;
+
+-/* re-entrant syslog default context data */
+-#define AUTOFS_SYSLOG_CONTEXT {-1, 0, 0, LOG_PID, (const char *)0, LOG_DAEMON, 0xff};
+-
+ #define MAX_OPEN_FILES 10240
+
+ static int umount_all(struct autofs_point *ap, int force);
+@@ -792,7 +788,6 @@ static void become_daemon(unsigned foreground)
+ {
+ FILE *pidfp;
+ char buf[MAX_ERR_BUF];
+- unsigned to_stderr = 0;
+ pid_t pid;
+
+ /* Don't BUSY any directories unnecessarily */
+@@ -809,7 +804,9 @@ static void become_daemon(unsigned foreground)
+ }
+
+ /* Detach from foreground process */
+- if (!foreground) {
++ if (foreground)
++ log_to_stderr();
++ else {
+ pid = fork();
+ if (pid > 0) {
+ int r;
+@@ -834,13 +831,8 @@ static void become_daemon(unsigned foreground)
+ fprintf(stderr, "setsid: %s", estr);
+ exit(1);
+ }
+- }
+-
+- /* Setup logging */
+- if (to_stderr)
+- log_to_stderr();
+- else
+ log_to_syslog();
++ }
+
+ /* Write pid file if requested */
+ if (pid_file) {
+@@ -929,7 +921,7 @@ static pthread_t do_signals(struct master *master, int sig)
+ if (status)
+ fatal(status);
+
+- status = pthread_create(&thid, &thread_attr_nodetach, do_notify_state, &r_sig);
++ status = pthread_create(&thid, &thread_attr, do_notify_state, &r_sig);
+ if (status) {
+ error(master->default_logging,
+ "mount state notify thread create failed");
+@@ -1045,7 +1037,6 @@ static int do_hup_signal(struct master *master, time_t age)
+ /* Deal with all the signal-driven events in the state machine */
+ static void *statemachine(void *arg)
+ {
+- pthread_t thid = 0;
+ sigset_t signalset;
+ int sig;
+
+@@ -1058,15 +1049,12 @@ static void *statemachine(void *arg)
+
+ switch (sig) {
+ case SIGTERM:
++ case SIGINT:
+ case SIGUSR2:
++ if (master_list_empty(master_list))
++ return NULL;
+ case SIGUSR1:
+- thid = do_signals(master_list, sig);
+- if (thid) {
+- pthread_join(thid, NULL);
+- if (master_list_empty(master_list))
+- return NULL;
+- thid = 0;
+- }
++ do_signals(master_list, sig);
+ break;
+
+ case SIGHUP:
+@@ -1181,6 +1169,10 @@ static void handle_mounts_cleanup(void *arg)
+
+ msg("shut down path %s", path);
+
++ /* If we are the last tell the state machine to shutdown */
++ if (!submount && master_list_empty(master_list))
++ pthread_kill(state_mach_thid, SIGTERM);
++
+ return;
+ }
+
+@@ -1375,7 +1367,7 @@ static void usage(void)
+ " -v --verbose be verbose\n"
+ " -d --debug log debuging info\n"
+ " -D --define define global macro variable\n"
+- /*" -f --foreground do not fork into background\n" */
++ " -f --foreground do not fork into background\n"
+ " -r --random-multimount-selection\n"
+ " use ramdom replicated server selection\n"
+ " -O --global-options\n"
+@@ -1650,14 +1642,6 @@ int main(int argc, char *argv[])
+ }
+ #endif
+
+- if (pthread_attr_init(&thread_attr_nodetach)) {
+- crit(LOGOPT_ANY,
+- "%s: failed to init thread attribute struct!",
+- program);
+- close(start_pipefd[1]);
+- exit(1);
+- }
+-
+ msg("Starting automounter version %s, master map %s",
+ version, master_list->name);
+ msg("using kernel protocol version %d.%02d",
+@@ -1702,6 +1686,7 @@ int main(int argc, char *argv[])
+ res = write(start_pipefd[1], pst_stat, sizeof(pst_stat));
+ close(start_pipefd[1]);
+
++ state_mach_thid = pthread_self();
+ statemachine(NULL);
+
+ master_kill(master_list);
+diff --git a/lib/log.c b/lib/log.c
+index e639e60..b747e12 100644
+--- a/lib/log.c
++++ b/lib/log.c
+@@ -27,9 +27,6 @@
+
+ #include "automount.h"
+
+-/* re-entrant syslog default context data */
+-#define AUTOFS_SYSLOG_CONTEXT {-1, 0, 0, LOG_PID, (const char *) 0, LOG_DAEMON, 0xff};
+-
+ /*
+ struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+ struct syslog_data *slc = &syslog_context;
+@@ -134,30 +131,40 @@ static void syslog_debug(unsigned int logopt, const char *msg, ...)
+ va_end(ap);
+ }
+
++static void to_stderr(unsigned int logopt, const char *msg, ...)
++{
++ va_list ap;
++ va_start(ap, msg);
++ vfprintf(stderr, msg, ap);
++ fputc('\n',stderr);
++ va_end(ap);
++}
++
+ void set_mnt_logging(struct autofs_point *ap)
+ {
+ unsigned int opt_verbose = ap->logopt & LOGOPT_VERBOSE;
+ unsigned int opt_debug = ap->logopt & LOGOPT_DEBUG;
+
+- if (opt_debug)
+- log_debug = syslog_debug;
++ if (opt_debug) {
++ if (logging_to_syslog)
++ log_debug = syslog_debug;
++ else
++ log_debug = to_stderr;
++ }
+
+ if (opt_verbose || opt_debug) {
+- log_info = syslog_info;
+- log_notice = syslog_notice;
+- log_warn = syslog_warn;
++ if (logging_to_syslog) {
++ log_info = syslog_info;
++ log_notice = syslog_notice;
++ log_warn = syslog_warn;
++ } else {
++ log_info = to_stderr;
++ log_notice = to_stderr;
++ log_warn = to_stderr;
++ }
+ }
+ }
+
+-static void to_stderr(unsigned int logopt, const char *msg, ...)
+-{
+- va_list ap;
+- va_start(ap, msg);
+- vfprintf(stderr, msg, ap);
+- fputc('\n',stderr);
+- va_end(ap);
+-}
+-
+ void log_to_syslog(void)
+ {
+ char buf[MAX_ERR_BUF];
+diff --git a/lib/master.c b/lib/master.c
+index 637ce04..abc3bc2 100644
+--- a/lib/master.c
++++ b/lib/master.c
+@@ -954,6 +954,7 @@ void master_notify_state_change(struct master *master, int sig)
+
+ switch (sig) {
+ case SIGTERM:
++ case SIGINT:
+ if (ap->state != ST_SHUTDOWN_PENDING &&
+ ap->state != ST_SHUTDOWN_FORCE) {
+ next = ST_SHUTDOWN_PENDING;
+diff --git a/man/automount.8 b/man/automount.8
+index da67a5c..e203a3e 100644
+--- a/man/automount.8
++++ b/man/automount.8
+@@ -47,6 +47,9 @@ Define a global macro substitution variable. Global definitions
+ are over-ridden macro definitions of the same name specified in
+ mount entries.
+ .TP
++.I "\-f, \-\-foreground"
++Run the daemon in the forground and log to stderr instead of syslog."
++.TP
+ .I "\-r, \-\-random-multimount-selection"
+ Enables the use of ramdom selection when choosing a host from a
+ list of replicated servers.
+diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
+index 9aac792..68e5dd7 100644
+--- a/modules/cyrus-sasl.c
++++ b/modules/cyrus-sasl.c
+@@ -197,7 +197,7 @@ get_server_SASL_mechanisms(LDAP *ld)
+ if (mechanisms == NULL) {
+ /* Well, that was a waste of time. */
+ msg("No SASL authentication mechanisms are supported"
+- " by the LDAP server.\n");
++ " by the LDAP server.");
+ return NULL;
+ }
+
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 4068561..c0f228b 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -857,17 +857,17 @@ int parse_ldap_config(struct lookup_context *ctxt)
+ ctxt->client_princ = client_princ;
+
+ debug(LOGOPT_NONE,
+- "ldap authentication configured with the following options:\n");
++ "ldap authentication configured with the following options:");
+ debug(LOGOPT_NONE,
+ "use_tls: %u, "
+ "tls_required: %u, "
+ "auth_required: %u, "
+- "sasl_mech: %s\n",
++ "sasl_mech: %s",
+ use_tls, tls_required, auth_required, authtype);
+ debug(LOGOPT_NONE,
+ "user: %s, "
+ "secret: %s, "
+- "client principal: %s\n",
++ "client principal: %s",
+ user, secret ? "specified" : "unspecified",
+ client_princ);
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 903e619..bc4d8fd 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -8,6 +8,7 @@
+ with existing downstream version 4 naming.
+ - fix mount point directory creation for bind mounts.
+ - add quoting for exports gathered by hosts map.
++- fix wait time resolution in alarm and state queue handlers.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/state.c b/daemon/state.c
+index 6c373c8..39f4497 100644
+--- a/daemon/state.c
++++ b/daemon/state.c
+@@ -894,6 +894,7 @@ static void *st_queue_handler(void *arg)
+ struct list_head *head;
+ struct list_head *p;
+ struct timespec wait;
++ struct timeval now;
+ int status, ret;
+
+ st_mutex_lock();
+@@ -904,8 +905,9 @@ static void *st_queue_handler(void *arg)
+ * entry is added.
+ */
+ head = &state_queue;
+- wait.tv_sec = time(NULL) + 1;
+- wait.tv_nsec = 0;
++ gettimeofday(&now, NULL);
++ wait.tv_sec = now.tv_sec + 1;
++ wait.tv_nsec = now.tv_usec * 1000;
+
+ while (list_empty(head)) {
+ status = pthread_cond_timedwait(&cond, &mutex, &wait);
+@@ -939,8 +941,9 @@ static void *st_queue_handler(void *arg)
+ }
+
+ while (1) {
+- wait.tv_sec = time(NULL) + 1;
+- wait.tv_nsec = 0;
++ gettimeofday(&now, NULL);
++ wait.tv_sec = now.tv_sec + 1;
++ wait.tv_nsec = now.tv_usec * 1000;
+
+ signaled = 0;
+ while (!signaled) {
+diff --git a/lib/alarm.c b/lib/alarm.c
+index c6c4ba3..90bf7aa 100755
+--- a/lib/alarm.c
++++ b/lib/alarm.c
+@@ -192,12 +192,14 @@ static void *alarm_handler(void *arg)
+ now = time(NULL);
+
+ if (first->time > now) {
++ struct timeval usecs;
+ /*
+ * Wait for alarm to trigger or a new alarm
+ * to be added.
+ */
++ gettimeofday(&usecs, NULL);
+ expire.tv_sec = first->time;
+- expire.tv_nsec = 0;
++ expire.tv_nsec = usecs.tv_usec * 1000;
+
+ status = pthread_cond_timedwait(&cond, &mutex, &expire);
+ if (status && status != ETIMEDOUT)
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index c486a7b..0fcdfd4 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -53,6 +53,7 @@
+ - add authentication option for using an external credential cache.
+ - expand support for the "%" hack.
+ - fix to quoting for exports gathered by hosts map.
++- use mount option "nosuid" for "-hosts" map unless "suid" is explicily specified.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index d488960..56aaa5d 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -195,6 +195,9 @@ For example, with an entry in the master map of
+ .hy
+ accessing /net/myserver will mount exports from myserver on directories below
+ /net/myserver.
++.P
++NOTE: mounts done from a hosts map will be mounted with the "nosuid" option
++unless the "suid" option is explicitly given in the master map entry.
+ .SH LDAP MAPS
+ If the map type \fBldap\fP is specified the mapname is of the form
+ \fB[//servername/]dn\fP, where the optional \fBservername\fP is
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 186e567..9a97329 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -496,6 +496,7 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ int rv, cur_state;
+ char *mountpoint;
+ char *what;
++ char *type;
+
+ if (*options == '\0')
+ options = NULL;
+@@ -585,6 +586,36 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ mountpoint = alloca(namelen + 1);
+ sprintf(mountpoint, "%.*s", namelen, name);
+
++ type = ap->entry->maps->type;
++ if (type && !strcmp(type, "hosts")) {
++ if (options) {
++ if (!strstr(options, "suid")) {
++ char *tmp = alloca(strlen(options) + 8);
++ if (!tmp) {
++ error(ap->logopt, MODPREFIX
++ "alloca failed for options");
++ if (nonstrict)
++ return -1;
++ return 1;
++ }
++ strcpy(tmp, options);
++ strcat(tmp, ",nosuid");
++ options = tmp;
++ }
++ } else {
++ char *tmp = alloca(7);
++ if (!tmp) {
++ error(ap->logopt,
++ MODPREFIX "alloca failed for options");
++ if (nonstrict)
++ return -1;
++ return 1;
++ }
++ strcpy(tmp, "nosuid");
++ options = tmp;
++ }
++ }
++
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ if (!strcmp(fstype, "nfs")) {
+ what = alloca(loclen + 1);
+diff --git a/samples/auto.master b/samples/auto.master
+index d4796a3..4995976 100644
+--- a/samples/auto.master
++++ b/samples/auto.master
+@@ -5,6 +5,11 @@
+ # For details of the format look at autofs(5).
+ #
+ /misc /etc/auto.misc
++#
++# NOTE: mounts done from a hosts map will be mounted with the
++# "nosuid" option unless the "suid" option is explicitly
++# given.
++#
+ /net -hosts
+ #
+ # Include central master map if it can be found using
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 09b0541..d8a6987 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -56,6 +56,7 @@
+ - use mount option "nosuid" for "-hosts" map unless "suid" is explicily specified.
+ - second attempt fixing quoting for exports gathered by hosts map.
+ - quell annoying "cannot open mount module" message.
++- fix for improve handling of server not available.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index a77068a..ab2dd0f 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -474,8 +474,12 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ MODPREFIX
+ "failed to read included master map %s",
+ master->name);
+- fclose(f);
+- return NSS_STATUS_UNAVAIL;
++ if (!master->recurse) {
++ master->depth--;
++ master->recurse = 0;
++ fclose(f);
++ return NSS_STATUS_UNAVAIL;
++ }
+ }
+ master->depth--;
+ master->recurse = 0;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 6379d18..a9e509d 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -48,6 +48,7 @@
+ - eliminate NULL proc ping for singleton host or local mounts.
+ - fix incorrect read/write size of startup status token (Matthias Koenig).
+ - fix off-by-one error for lookup of map keys exactly 255 characters long.
++- improve handling of server not available.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 0be10d3..eb72411 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -298,8 +298,6 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a
+
+ status = lookup->lookup_read_map(ap, age, lookup->context);
+
+- map->stale = 0;
+-
+ /*
+ * For maps that don't support enumeration return success
+ * and do whatever we must to have autofs function with an
+@@ -533,6 +531,10 @@ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time
+ if (result == NSS_STATUS_UNKNOWN)
+ continue;
+
++ /* Don't try to update the map cache if it's unavailable */
++ if (result == NSS_STATUS_UNAVAIL)
++ map->stale = 0;
++
+ if (result == NSS_STATUS_SUCCESS) {
+ at_least_one = 1;
+ result = NSS_STATUS_TRYAGAIN;
+@@ -553,7 +555,7 @@ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time
+ }
+ pthread_cleanup_pop(1);
+
+- if (!result || at_least_one)
++ if (!result || at_least_one)
+ return 1;
+
+ return 0;
+diff --git a/daemon/state.c b/daemon/state.c
+index cf07aac..5bccfef 100644
+--- a/daemon/state.c
++++ b/daemon/state.c
+@@ -432,6 +432,7 @@ static void *do_readmap(void *arg)
+ me = cache_enumerate(mc, me);
+ }
+ pthread_cleanup_pop(1);
++ map->stale = 0;
+ map = map->next;
+ }
+ pthread_cleanup_pop(1);
+diff --git a/include/automount.h b/include/automount.h
+index fa5cd97..133fd32 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -121,6 +121,7 @@ struct autofs_point;
+ #define CHE_MISSING 0x0008
+ #define CHE_COMPLETED 0x0010
+ #define CHE_DUPLICATE 0x0020
++#define CHE_UNAVAIL 0x0040
+
+ #define HASHSIZE 77
+ #define NEGATIVE_TIMEOUT 10
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index 550bf5c..a77068a 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -469,11 +469,14 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ master->recurse = 1;;
+ master->depth++;
+ status = lookup_nss_read_master(master, age);
+- if (!status)
++ if (!status) {
+ warn(logopt,
+ MODPREFIX
+ "failed to read included master map %s",
+ master->name);
++ fclose(f);
++ return NSS_STATUS_UNAVAIL;
++ }
+ master->depth--;
+ master->recurse = 0;
+
+@@ -484,6 +487,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ if (!buffer) {
+ error(logopt,
+ MODPREFIX "could not malloc parse buffer");
++ fclose(f);
+ return NSS_STATUS_UNAVAIL;
+ }
+ memset(buffer, 0, blen);
+@@ -721,9 +725,12 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+
+ /* Gim'ee some o' that 16k stack baby !! */
+ status = lookup_nss_read_map(ap, inc_source, age);
+- if (!status)
++ if (!status) {
+ warn(ap->logopt,
+ "failed to read included map %s", key);
++ fclose(f);
++ return NSS_STATUS_UNAVAIL;
++ }
+ } else {
+ char *s_key;
+
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index b8484a2..7effbf1 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -1755,7 +1755,7 @@ static int lookup_one(struct autofs_point *ap,
+ /* Initialize the LDAP context. */
+ ldap = do_reconnect(ap->logopt, ctxt);
+ if (!ldap)
+- return CHE_FAIL;
++ return CHE_UNAVAIL;
+
+ debug(ap->logopt,
+ MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn);
+@@ -1999,6 +1999,21 @@ static int check_map_indirect(struct autofs_point *ap,
+ if (ret == CHE_FAIL) {
+ pthread_setcancelstate(cur_state, NULL);
+ return NSS_STATUS_NOTFOUND;
++ } else if (ret == CHE_UNAVAIL) {
++ /*
++ * If the server is down and the entry exists in the cache
++ * and belongs to this map return success and use the entry.
++ */
++ struct mapent *exists = cache_lookup(mc, key);
++ if (exists && exists->source == source) {
++ pthread_setcancelstate(cur_state, NULL);
++ return NSS_STATUS_SUCCESS;
++ }
++
++ warn(ap->logopt,
++ MODPREFIX "lookup for %s failed: connection failed", key);
++
++ return NSS_STATUS_UNAVAIL;
+ }
+ pthread_setcancelstate(cur_state, NULL);
+
+diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
+index fee8b16..628ffcf 100644
+--- a/modules/lookup_nisplus.c
++++ b/modules/lookup_nisplus.c
+@@ -385,9 +385,18 @@ static int check_map_indirect(struct autofs_point *ap,
+ return NSS_STATUS_NOTFOUND;
+
+ if (ret < 0) {
++ /*
++ * If the server is down and the entry exists in the cache
++ * and belongs to this map return success and use the entry.
++ */
++ exists = cache_lookup(mc, key);
++ if (exists && exists->source == source)
++ return NSS_STATUS_SUCCESS;
++
+ warn(ap->logopt,
+ MODPREFIX "lookup for %s failed: %s",
+ key, nis_sperrno(-ret));
++
+ return NSS_STATUS_UNAVAIL;
+ }
+
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index 5f4f95f..f5097dc 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -239,6 +239,9 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ MODPREFIX "read of master map %s failed: %s",
+ mapname, yperr_string(err));
+
++ if (err == YPERR_PMAP || err == YPERR_YPSERV)
++ return NSS_STATUS_UNAVAIL;
++
+ return NSS_STATUS_NOTFOUND;
+ }
+
+@@ -336,6 +339,9 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
+ MODPREFIX "read of map %s failed: %s",
+ ap->path, yperr_string(err));
+
++ if (err == YPERR_PMAP || err == YPERR_YPSERV)
++ return NSS_STATUS_UNAVAIL;
++
+ return NSS_STATUS_NOTFOUND;
+ }
+
+@@ -481,9 +487,18 @@ static int check_map_indirect(struct autofs_point *ap,
+ return NSS_STATUS_NOTFOUND;
+
+ if (ret < 0) {
++ /*
++ * If the server is down and the entry exists in the cache
++ * and belongs to this map return success and use the entry.
++ */
++ exists = cache_lookup(mc, key);
++ if (exists && exists->source == source)
++ return NSS_STATUS_SUCCESS;
++
+ warn(ap->logopt,
+ MODPREFIX "lookup for %s failed: %s",
+ key, yperr_string(-ret));
++
+ return NSS_STATUS_UNAVAIL;
+ }
+
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index aa5d1c1..98d082c 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -12,6 +12,7 @@
+ - fix handling of quoted slash alone.
+ - fix parse confusion between attribute and attribute value.
+ - fix version passed to get_supported_ver_and_cost.
++- mark map instances stale so they aren't "cleaned" during updates.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 70b9e02..4f2b318 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -325,6 +325,7 @@ static int read_file_source_instance(struct autofs_point *ap, struct map_source
+ instance->recurse = map->recurse;
+ instance->depth = map->depth;
+ }
++ instance->stale = map->stale;
+
+ return do_read_map(ap, instance, age);
+ }
+@@ -346,6 +347,7 @@ static int read_source_instance(struct autofs_point *ap, struct map_source *map,
+ instance->recurse = map->recurse;
+ instance->depth = map->depth;
+ }
++ instance->stale = map->stale;
+
+ return do_read_map(ap, instance, age);
+ }
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 2c815e7..f8260b1 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -43,6 +43,7 @@
+ - when default master map, auto.master, is used also check for auto_master.
+ - fix schema selection in LDAP schema discovery.
+ - update negative mount timeout handling.
++- fix large group handling (Ryan Thomas).
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 4ab4204..88e59ab 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -1218,11 +1218,11 @@ static void *do_mount_direct(void *arg)
+ struct passwd *ppw = &pw;
+ struct passwd **pppw = &ppw;
+ struct group gr;
+- struct group *pgr = &gr;
+- struct group **ppgr = &pgr;
++ struct group *pgr;
++ struct group **ppgr;
+ char *pw_tmp, *gr_tmp;
+ struct thread_stdenv_vars *tsv;
+- int tmplen;
++ int tmplen, grplen;
+ struct stat st;
+ int status, state;
+
+@@ -1326,7 +1326,7 @@ static void *do_mount_direct(void *arg)
+
+ /* Try to get group info */
+
+- tmplen = sysconf(_SC_GETGR_R_SIZE_MAX);
++ grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (tmplen < 0) {
+ error(ap->logopt, "failed to get buffer size for getgrgid_r");
+ free(tsv->user);
+@@ -1335,16 +1335,28 @@ static void *do_mount_direct(void *arg)
+ goto cont;
+ }
+
+- gr_tmp = malloc(tmplen + 1);
+- if (!gr_tmp) {
+- error(ap->logopt, "failed to malloc buffer for getgrgid_r");
+- free(tsv->user);
+- free(tsv->home);
+- free(tsv);
+- goto cont;
++ gr_tmp = NULL;
++ tmplen = grplen;
++ while (1) {
++ char *tmp = realloc(gr_tmp, tmplen + 1);
++ if (!tmp) {
++ error(ap->logopt, "failed to malloc buffer for getgrgid_r");
++ if (gr_tmp)
++ free(gr_tmp);
++ free(tsv->user);
++ free(tsv->home);
++ free(tsv);
++ goto cont;
++ }
++ gr_tmp = tmp;
++ pgr = &gr;
++ ppgr = &pgr;
++ status = getgrgid_r(mt->gid, pgr, gr_tmp, tmplen, ppgr);
++ if (status != ERANGE)
++ break;
++ tmplen += grplen;
+ }
+
+- status = getgrgid_r(mt->gid, pgr, gr_tmp, tmplen, ppgr);
+ if (status || !pgr) {
+ error(ap->logopt, "failed to get group info from getgrgid_r");
+ free(tsv->user);
+diff --git a/daemon/indirect.c b/daemon/indirect.c
+index 5c422c8..f6b93d0 100644
+--- a/daemon/indirect.c
++++ b/daemon/indirect.c
+@@ -666,11 +666,11 @@ static void *do_mount_indirect(void *arg)
+ struct passwd *ppw = &pw;
+ struct passwd **pppw = &ppw;
+ struct group gr;
+- struct group *pgr = &gr;
+- struct group **ppgr = &pgr;
++ struct group *pgr;
++ struct group **ppgr;
+ char *pw_tmp, *gr_tmp;
+ struct thread_stdenv_vars *tsv;
+- int len, tmplen, status, state;
++ int len, tmplen, grplen, status, state;
+
+ mt = (struct pending_args *) arg;
+
+@@ -771,7 +771,7 @@ static void *do_mount_indirect(void *arg)
+
+ /* Try to get group info */
+
+- tmplen = sysconf(_SC_GETGR_R_SIZE_MAX);
++ grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (tmplen < 0) {
+ error(ap->logopt, "failed to get buffer size for getgrgid_r");
+ free(tsv->user);
+@@ -780,16 +780,28 @@ static void *do_mount_indirect(void *arg)
+ goto cont;
+ }
+
+- gr_tmp = malloc(tmplen + 1);
+- if (!gr_tmp) {
+- error(ap->logopt, "failed to malloc buffer for getgrgid_r");
+- free(tsv->user);
+- free(tsv->home);
+- free(tsv);
+- goto cont;
++ gr_tmp = NULL;
++ tmplen = grplen;
++ while (1) {
++ char *tmp = realloc(gr_tmp, tmplen + 1);
++ if (!tmp) {
++ error(ap->logopt, "failed to malloc buffer for getgrgid_r");
++ if (gr_tmp)
++ free(gr_tmp);
++ free(tsv->user);
++ free(tsv->home);
++ free(tsv);
++ goto cont;
++ }
++ gr_tmp = tmp;
++ pgr = &gr;
++ ppgr = &pgr;
++ status = getgrgid_r(mt->gid, pgr, gr_tmp, tmplen, ppgr);
++ if (status != ERANGE)
++ break;
++ tmplen += grplen;
+ }
+
+- status = getgrgid_r(mt->gid, pgr, gr_tmp, tmplen, ppgr);
+ if (status || !pgr) {
+ error(ap->logopt, "failed to get group info from getgrgid_r");
+ free(tsv->user);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 054d4df..ef549cf 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -22,6 +22,7 @@
+ - add LDAP schema discovery if no schema is configured.
+ - add random selection as a master map entry option.
+ - fix couple of edge case parse fails of timeout option.
++- check for "*" when looking up wildcard in LDAP.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index d5e666b..a7b315e 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -1500,7 +1500,7 @@ static int lookup_one(struct autofs_point *ap,
+ *qKey = '/';
+
+ /* Build a query string. */
+- l = strlen(class) + 2*strlen(entry) + strlen(qKey) + 29;
++ l = strlen(class) + 3*strlen(entry) + strlen(qKey) + 35;
+
+ query = alloca(l);
+ if (query == NULL) {
+@@ -1514,7 +1514,7 @@ static int lookup_one(struct autofs_point *ap,
+ * whose entry is equal to qKey.
+ */
+ ql = sprintf(query,
+- "(&(objectclass=%s)(|(%s=%s)(%s=/)))", class, entry, qKey, entry);
++ "(&(objectclass=%s)(|(%s=%s)(%s=/)(%s=\\2A)))", class, entry, qKey, entry, entry);
+ if (ql >= l) {
+ error(ap->logopt,
+ MODPREFIX "error forming query string");
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index da8c599..c6ab15f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -15,6 +15,7 @@
+ - mark map instances stale so they aren't "cleaned" during updates.
+ - fix large file compile time option.
+ - don't fail on empty master map.
++- add support for the "%" hack for case insensitive attribute schemas.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index de8d515..a412797 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -1210,50 +1210,68 @@ static int read_one_map(struct autofs_point *ap,
+ }
+
+ /*
+- * By definition keys must be unique within
+- * each map entry
++ * By definition keys should be unique within each map entry,
++ * but as always there are exceptions.
+ */
+ k_val = NULL;
+ k_len = 0;
+
+ /*
+- * Keys must be unique so, in general, there shouldn't be
++ * Keys should be unique so, in general, there shouldn't be
+ * more than one attribute value. We make an exception for
+ * wildcard entries as people may have values for '*' or
+ * '/' for compaibility reasons. We use the '/' as the
+ * wildcard in LDAP but allow '*' as well to allow for
+ * people using older schemas that allow '*' as a key
+- * value.
++ * value. Another case where there can be multiple key
++ * values is when people have used the "%" hack to specify
++ * case matching ctriteria in a caase insensitive attribute.
+ */
+ count = ldap_count_values_len(bvKey);
+- if (count > 2) {
+- error(ap->logopt,
+- MODPREFIX
+- "key %.*s has duplicate entries - ignoring",
+- bvKey[0]->bv_len, bvKey[0]->bv_val);
+- goto next;
+- } else if (count == 2) {
++ if (count > 1) {
+ unsigned int i;
+
+ /* Check for the "/" and "*" and use as "/" if found */
+ for (i = 0; i < count; i++) {
+- /* check for wildcard */
+- if (bvKey[i]->bv_len != 1)
++ bvKey[i]->bv_val[bvKey[i]->bv_len] = '\0';
++
++ /*
++ * If multiple entries are present they could
++ * be the result of people using the "%" hack so
++ * ignore them.
++ */
++ if (strchr(bvKey[i]->bv_val, '%'))
+ continue;
+- if (*bvKey[i]->bv_val != '/' &&
+- *bvKey[i]->bv_val != '*')
+- continue;
+- /* always use '/' internally */
+- *bvKey[i]->bv_val = '/';
++
++ /* check for wildcard */
++ if (bvKey[i]->bv_len == 1 &&
++ (*bvKey[i]->bv_val == '/' ||
++ *bvKey[i]->bv_val == '*')) {
++ /* always use '/' internally */
++ *bvKey[i]->bv_val = '/';
++ k_val = bvKey[i]->bv_val;
++ k_len = 1;
++ break;
++ }
++
++ /*
++ * We have a result from LDAP so this is a
++ * valid entry. Set the result to the LDAP
++ * key that isn't a wildcard and doesn't have
++ * any "%" hack values present. This should be
++ * the case insensitive match string for the
++ * nis schema, the default value.
++ */
+ k_val = bvKey[i]->bv_val;
+- k_len = 1;
++ k_len = bvKey[i]->bv_len;
++
+ break;
+ }
+
+ if (!k_val) {
+ error(ap->logopt,
+ MODPREFIX
+- "key %.*s has duplicate entries - ignoring",
++ "invalid entry %.*s - ignoring",
+ bvKey[0]->bv_len, bvKey[0]->bv_val);
+ goto next;
+ }
+@@ -1495,7 +1513,10 @@ static int lookup_one(struct autofs_point *ap,
+ continue;
+ }
+
+- /* By definition keys must be unique within each map entry */
++ /*
++ * By definition keys should be unique within each map entry,
++ * but as always there are exceptions.
++ */
+ k_val = NULL;
+ k_len = 0;
+
+@@ -1506,37 +1527,53 @@ static int lookup_one(struct autofs_point *ap,
+ * '/' for compaibility reasons. We use the '/' as the
+ * wildcard in LDAP but allow '*' as well to allow for
+ * people using older schemas that allow '*' as a key
+- * value.
++ * value. Another case where there can be multiple key
++ * values is when people have used the "%" hack to specify
++ * case matching ctriteria in a caase insensitive attribute.
+ */
+ count = ldap_count_values_len(bvKey);
+- if (count > 2) {
+- error(ap->logopt,
+- MODPREFIX
+- "key %.*s has duplicate entries - ignoring",
+- bvKey[0]->bv_len, bvKey[0]->bv_val);
+- goto next;
+- } else if (count == 2) {
++ if (count > 1) {
+ unsigned int i;
+
+ /* Check for the "/" and "*" and use as "/" if found */
+ for (i = 0; i < count; i++) {
+- /* check for wildcard */
+- if (bvKey[i]->bv_len != 1)
+- continue;
+- if (*bvKey[i]->bv_val != '/' &&
+- *bvKey[i]->bv_val != '*')
++ bvKey[i]->bv_val[bvKey[i]->bv_len] = '\0';
++
++ /*
++ * If multiple entries are present they could
++ * be the result of people using the "%" hack so
++ * ignore them.
++ */
++ if (strchr(bvKey[i]->bv_val, '%'))
+ continue;
+- /* always use '/' internally */
+- *bvKey[i]->bv_val = '/';
+- k_val = bvKey[i]->bv_val;
+- k_len = 1;
++
++ /* check for wildcard */
++ if (bvKey[i]->bv_len == 1 &&
++ (*bvKey[i]->bv_val == '/' ||
++ *bvKey[i]->bv_val == '*')) {
++ /* always use '/' internally */
++ *bvKey[i]->bv_val = '/';
++ k_val = bvKey[i]->bv_val;
++ k_len = 1;
++ break;
++ }
++
++ /*
++ * The key was matched by LDAP so this is a
++ * valid entry. Set the result key to the
++ * lookup key to provide the mixed case
++ * matching provided by the "%" hack.
++ */
++ k_val = qKey;
++ k_len = strlen(qKey);
++
+ break;
+ }
+
+ if (!k_val) {
+ error(ap->logopt,
+- MODPREFIX "key %.*s has duplicate entries",
+- bvKey[0]->bv_len, bvKey[0]->bv_val);
++ MODPREFIX "no valid key found for %.*s",
++ qKey_len, qKey);
+ ret = CHE_FAIL;
+ goto next;
+ }
--- /dev/null
+diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
+index 8299b55..85f4e34 100644
+--- a/redhat/autofs.sysconfig.in
++++ b/redhat/autofs.sysconfig.in
+@@ -21,9 +21,12 @@ BROWSE_MODE="no"
+ #
+ #LOGGING="none"
+ #
+-# Define the default LDAP schema to use for lookups
++# Define the LDAP schema to used for lookups
+ #
+-# System default
++# If no schema is set autofs will check each of the schemas
++# below in the order given to try and locate an appropriate
++# basdn for lookups. If you want to minimize the number of
++# queries to the server set the values here.
+ #
+ #MAP_OBJECT_CLASS="nisMap"
+ #ENTRY_OBJECT_CLASS="nisObject"
+diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
+index 8299b55..85f4e34 100644
+--- a/samples/autofs.conf.default.in
++++ b/samples/autofs.conf.default.in
+@@ -21,9 +21,12 @@ BROWSE_MODE="no"
+ #
+ #LOGGING="none"
+ #
+-# Define the default LDAP schema to use for lookups
++# Define the LDAP schema to used for lookups
+ #
+-# System default
++# If no schema is set autofs will check each of the schemas
++# below in the order given to try and locate an appropriate
++# basdn for lookups. If you want to minimize the number of
++# queries to the server set the values here.
+ #
+ #MAP_OBJECT_CLASS="nisMap"
+ #ENTRY_OBJECT_CLASS="nisObject"
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 08afa7c..c208b31 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -24,6 +24,7 @@
+ - fix couple of edge case parse fails of timeout option.
+ - check for "*" when looking up wildcard in LDAP.
+ - fix LDAP schema discovery.
++- add SEARCH_BASE configuration option.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/include/defaults.h b/include/defaults.h
+index 9aec11a..0984b1c 100644
+--- a/include/defaults.h
++++ b/include/defaults.h
+@@ -37,6 +37,9 @@
+ #define DEFAULT_APPEND_OPTIONS 1
+ #define DEFAULT_AUTH_CONF_FILE AUTOFS_MAP_DIR "/autofs_ldap_auth.conf"
+
++struct ldap_schema;
++struct ldap_searchdn;
++
+ unsigned int defaults_read_config(void);
+ const char *defaults_get_master_map(void);
+ unsigned int defaults_get_timeout(void);
+@@ -45,6 +48,8 @@ unsigned int defaults_get_logging(void);
+ const char *defaults_get_ldap_server(void);
+ struct ldap_schema *defaults_get_default_schema(void);
+ struct ldap_schema *defaults_get_schema(void);
++struct ldap_searchdn *defaults_get_searchdns(void);
++void defaults_free_searchdns(struct ldap_searchdn *);
+ unsigned int defaults_get_append_options(void);
+ const char *defaults_get_auth_conf_file(void);
+
+diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
+index 1378b9e..1a924be 100644
+--- a/include/lookup_ldap.h
++++ b/include/lookup_ldap.h
+@@ -18,6 +18,11 @@ struct ldap_schema {
+ char *value_attr;
+ };
+
++struct ldap_searchdn {
++ char *basedn;
++ struct ldap_searchdn *next;
++};
++
+ struct lookup_context {
+ char *mapname;
+
+@@ -32,6 +37,10 @@ struct lookup_context {
+ /* LDAP lookup configuration */
+ struct ldap_schema *schema;
+
++ /* List of base dns for searching */
++ char *cur_host;
++ struct ldap_searchdn *sdns;
++
+ /* TLS and SASL authentication information */
+ char *auth_conf;
+ unsigned use_tls;
+diff --git a/lib/defaults.c b/lib/defaults.c
+index b146f13..c2f86c0 100644
+--- a/lib/defaults.c
++++ b/lib/defaults.c
+@@ -32,6 +32,8 @@
+
+ #define ENV_LDAP_SERVER "LDAP_SERVER"
+
++#define SEARCH_BASE "SEARCH_BASE"
++
+ #define ENV_NAME_MAP_OBJ_CLASS "MAP_OBJECT_CLASS"
+ #define ENV_NAME_ENTRY_OBJ_CLASS "ENTRY_OBJECT_CLASS"
+ #define ENV_NAME_MAP_ATTR "MAP_ATTRIBUTE"
+@@ -130,6 +132,52 @@ static int check_set_config_value(const char *res, const char *name, const char
+ return 0;
+ }
+
++static int parse_line(char *line, char **res, char **value)
++{
++ volatile char *key, *val, *trailer;
++ int len;
++
++ key = line;
++
++ if (*key == '#' || !isalpha(*key))
++ return 0;
++
++ while (*key && *key == ' ')
++ key++;
++
++ if (!key)
++ return 0;
++
++ if (!(val = strchr(key, '=')))
++ return 0;
++
++ *val++ = '\0';
++
++ while (*val && (*val == '"' || isblank(*val)))
++ val++;
++
++ len = strlen(val);
++
++ if (val[len - 1] == '\n') {
++ val[len - 1] = '\0';
++ len--;
++ }
++
++ trailer = strchr(val, '#');
++ if (!trailer)
++ trailer = val + len - 1;
++ else
++ trailer--;
++
++ while (*trailer && (*trailer == '"' || isblank(*trailer)))
++ *(trailer--) = '\0';;
++
++ *res = key;
++ *value = val;
++
++ return 1;
++}
++
+ /*
+ * Read config env variables and check they have been set.
+ *
+@@ -141,61 +189,30 @@ unsigned int defaults_read_config(void)
+ {
+ FILE *f;
+ char buf[MAX_LINE_LEN];
+- char *res, *value;
++ char *res;
+
+ f = fopen(DEFAULTS_CONFIG_FILE, "r");
+ if (!f)
+ return 0;
+
+ while ((res = fgets(buf, MAX_LINE_LEN, f))) {
+- char *trailer;
+- int len;
+-
+- if (*res == '#' || !isalpha(*res))
+- continue;
+-
+- while (*res && *res == ' ')
+- res++;
+-
+- if (!res)
+- continue;
++ char *key, *value;
+
+- if (!(value = strchr(res, '=')))
++ if (!parse_line(res, &key, &value))
+ continue;
+
+- *value++ = '\0';
+-
+- while (*value && (*value == '"' || isblank(*value)))
+- value++;
+-
+- len = strlen(value);
+-
+- if (value[len - 1] == '\n') {
+- value[len - 1] = '\0';
+- len--;
+- }
+-
+- trailer = strchr(value, '#');
+- if (!trailer)
+- trailer = value + len - 1;
+- else
+- trailer--;
+-
+- while (*trailer && (*trailer == '"' || isblank(*trailer)))
+- *(trailer--) = '\0';;
+-
+- if (check_set_config_value(res, ENV_NAME_MASTER_MAP, value) ||
+- check_set_config_value(res, ENV_NAME_TIMEOUT, value) ||
+- check_set_config_value(res, ENV_NAME_BROWSE_MODE, value) ||
+- check_set_config_value(res, ENV_NAME_LOGGING, value) ||
+- check_set_config_value(res, ENV_LDAP_SERVER, value) ||
+- check_set_config_value(res, ENV_NAME_MAP_OBJ_CLASS, value) ||
+- check_set_config_value(res, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
+- check_set_config_value(res, ENV_NAME_MAP_ATTR, value) ||
+- check_set_config_value(res, ENV_NAME_ENTRY_ATTR, value) ||
+- check_set_config_value(res, ENV_NAME_VALUE_ATTR, value) ||
+- check_set_config_value(res, ENV_APPEND_OPTIONS, value) ||
+- check_set_config_value(res, ENV_AUTH_CONF_FILE, value))
++ if (check_set_config_value(key, ENV_NAME_MASTER_MAP, value) ||
++ check_set_config_value(key, ENV_NAME_TIMEOUT, value) ||
++ check_set_config_value(key, ENV_NAME_BROWSE_MODE, value) ||
++ check_set_config_value(key, ENV_NAME_LOGGING, value) ||
++ check_set_config_value(key, ENV_LDAP_SERVER, value) ||
++ check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value) ||
++ check_set_config_value(key, ENV_NAME_ENTRY_OBJ_CLASS, value) ||
++ check_set_config_value(key, ENV_NAME_MAP_ATTR, value) ||
++ check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value) ||
++ check_set_config_value(key, ENV_NAME_VALUE_ATTR, value) ||
++ check_set_config_value(key, ENV_APPEND_OPTIONS, value) ||
++ check_set_config_value(key, ENV_AUTH_CONF_FILE, value))
+ ;
+ }
+
+@@ -336,6 +353,86 @@ struct ldap_schema *defaults_get_default_schema(void)
+ return schema;
+ }
+
++static struct ldap_searchdn *alloc_searchdn(const char *value)
++{
++ struct ldap_searchdn *sdn;
++ char *val;
++
++ sdn = malloc(sizeof(struct ldap_searchdn));
++ if (!sdn)
++ return NULL;
++
++ val = strdup(value);
++ if (!val) {
++ free(sdn);
++ return NULL;
++ }
++
++ sdn->basedn = val;
++ sdn->next = NULL;
++
++ return sdn;
++}
++
++void defaults_free_searchdns(struct ldap_searchdn *sdn)
++{
++ struct ldap_searchdn *this = sdn;
++ struct ldap_searchdn *next;
++
++ next = this;
++ while (this) {
++ next = this->next;
++ free(this->basedn);
++ free(this);
++ this = next;
++ }
++
++ return;
++}
++
++struct ldap_searchdn *defaults_get_searchdns(void)
++{
++ FILE *f;
++ char buf[MAX_LINE_LEN];
++ char *res;
++ struct ldap_searchdn *sdn, *last;
++
++ f = fopen(DEFAULTS_CONFIG_FILE, "r");
++ if (!f)
++ return NULL;
++
++ sdn = last = NULL;
++
++ while ((res = fgets(buf, MAX_LINE_LEN, f))) {
++ char *key, *value;
++
++ if (!parse_line(res, &key, &value))
++ continue;
++
++ if (!strcasecmp(key, SEARCH_BASE)) {
++ struct ldap_searchdn *new = alloc_searchdn(value);
++
++ if (!new) {
++ defaults_free_searchdns(sdn);
++ return NULL;
++ }
++
++ if (!last)
++ last = new;
++ else {
++ last->next = new;
++ last = new;
++ }
++
++ if (!sdn)
++ sdn = new;
++ }
++ }
++
++ fclose(f);
++ return sdn;
++}
++
+ struct ldap_schema *defaults_get_schema(void)
+ {
+ struct ldap_schema *schema;
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index ab5ab1e..0cb2f07 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -230,6 +230,11 @@ values must be set, any partial schema specification will be ignored.
+ .P
+ The configuration settings available are:
+ .TP
++.B SEARCH_BASE
++The base dn to use when searching for amap base dn. This entry may be
++given multiple times and each will be checked for a map base dn in
++the order they occur in the configuration.
++.TP
+ .B MAP_OBJECT_CLASS
+ The map object class. In the \fBnisMap\fP schema this corresponds to the class
+ \fBnisMap\fP and in the \fBautomountMap\fP schema it corresponds to the class
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 9c18ca1..da52e71 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -171,10 +171,207 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
+ return ldap;
+ }
+
++static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
++{
++ char buf[PARSE_MAX_BUF];
++ char *query, *dn;
++ LDAPMessage *result = NULL, *e;
++ struct ldap_searchdn *sdns = NULL;
++ char *attrs[2];
++ int scope;
++ int rv, l;
++
++ attrs[0] = LDAP_NO_ATTRS;
++ attrs[1] = NULL;
++
++ if (!ctxt->mapname && !ctxt->base) {
++ error(LOGOPT_ANY, MODPREFIX "no master map to lookup");
++ return 0;
++ }
++
++ /* Build a query string. */
++ l = strlen("(objectclass=)") + strlen(class) + 1;
++ if (ctxt->mapname)
++ l += strlen(key) + strlen(ctxt->mapname) + strlen("(&(=))");
++
++ query = alloca(l);
++ if (query == NULL) {
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
++ return NSS_STATUS_UNAVAIL;
++ }
++
++ /*
++ * If we have a master mapname construct a query using it
++ * otherwise assume the base dn will catch it.
++ */
++ if (ctxt->mapname) {
++ if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
++ key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
++ debug(LOGOPT_NONE,
++ MODPREFIX "error forming query string");
++ return 0;
++ }
++ scope = LDAP_SCOPE_SUBTREE;
++ } else {
++ if (sprintf(query, "(objectclass=%s)", class) >= l) {
++ debug(LOGOPT_NONE,
++ MODPREFIX "error forming query string");
++ return 0;
++ }
++ scope = LDAP_SCOPE_SUBTREE;
++ }
++ query[l] = '\0';
++
++ if (!ctxt->base) {
++ sdns = defaults_get_searchdns();
++ if (sdns)
++ ctxt->sdns = sdns;
++ }
++
++ if (!sdns)
++ rv = ldap_search_s(ldap, ctxt->base,
++ scope, query, attrs, 0, &result);
++ else {
++ struct ldap_searchdn *this = sdns;
++
++ debug(LOGOPT_NONE, MODPREFIX
++ "check search base list");
++
++ while (this) {
++ rv = ldap_search_s(ldap, this->basedn,
++ scope, query, attrs, 0, &result);
++
++ if ((rv == LDAP_SUCCESS) && result) {
++ debug(LOGOPT_NONE, MODPREFIX
++ "found search base under %s",
++ this->basedn);
++ break;
++ }
++
++ this = this->next;
++
++ if (result) {
++ ldap_msgfree(result);
++ result = NULL;
++ }
++ }
++ }
++
++ if ((rv != LDAP_SUCCESS) || !result) {
++ error(LOGOPT_NONE,
++ MODPREFIX "query failed for %s: %s",
++ query, ldap_err2string(rv));
++ return 0;
++ }
++
++ e = ldap_first_entry(ldap, result);
++ if (e) {
++ dn = ldap_get_dn(ldap, e);
++ debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
++ ldap_msgfree(result);
++ } else {
++ debug(LOGOPT_NONE,
++ MODPREFIX "query succeeded, no matches for %s",
++ query);
++ ldap_msgfree(result);
++ return 0;
++ }
++
++ ctxt->qdn = dn;
++
++ return 1;
++}
++
++static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
++{
++ struct ldap_schema *schema;
++ char *mc, *ma, *ec, *ea, *va;
++
++ mc = strdup(s->map_class);
++ if (!mc)
++ return NULL;
++
++ ma = strdup(s->map_attr);
++ if (!ma) {
++ free(mc);
++ return NULL;
++ }
++
++ ec = strdup(s->entry_class);
++ if (!ec) {
++ free(mc);
++ free(ma);
++ return NULL;
++ }
++
++ ea = strdup(s->entry_attr);
++ if (!ea) {
++ free(mc);
++ free(ma);
++ free(ec);
++ return NULL;
++ }
++
++ va = strdup(s->value_attr);
++ if (!va) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ return NULL;
++ }
++
++ schema = malloc(sizeof(struct ldap_schema));
++ if (!schema) {
++ free(mc);
++ free(ma);
++ free(ec);
++ free(ea);
++ free(va);
++ return NULL;
++ }
++
++ schema->map_class = mc;
++ schema->map_attr = ma;
++ schema->entry_class = ec;
++ schema->entry_attr = ea;
++ schema->value_attr = va;
++
++ return schema;
++}
++
++static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
++{
++ struct ldap_schema *schema;
++ unsigned int i;
++
++ if (ctxt->schema)
++ return 0;
++
++ for (i = 0; i < common_schema_count; i++) {
++ const char *class = common_schema[i].map_class;
++ const char *key = common_schema[i].map_attr;
++ if (get_query_dn(ldap, ctxt, class, key)) {
++ schema = alloc_common_schema(&common_schema[i]);
++ if (!schema) {
++ error(LOGOPT_ANY,
++ MODPREFIX "failed to allocate schema");
++ return 0;
++ }
++ ctxt->schema = schema;
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
+ static LDAP *do_connect(struct lookup_context *ctxt)
+ {
+ LDAP *ldap;
+- int rv;
++ char *host = NULL, *nhost;
++ int rv, need_base = 1;
+
+ ldap = init_ldap_connection(ctxt);
+ if (!ldap)
+@@ -204,6 +401,61 @@ static LDAP *do_connect(struct lookup_context *ctxt)
+ return NULL;
+ }
+
++ rv = ldap_get_option(ldap, LDAP_OPT_HOST_NAME, &host);
++ if (rv != LDAP_SUCCESS || !host) {
++ unbind_ldap_connection(ldap, ctxt);
++ debug(LOGOPT_ANY, "failed to get hostname for connection");
++ return NULL;
++ }
++
++ nhost = strdup(host);
++ if (!nhost) {
++ unbind_ldap_connection(ldap, ctxt);
++ debug(LOGOPT_ANY, "failed to alloc context for hostname");
++ return NULL;
++ }
++ ldap_memfree(host);
++
++ if (!ctxt->cur_host) {
++ ctxt->cur_host = nhost;
++ /* Check if schema defined in conf first time only */
++ ctxt->schema = defaults_get_schema();
++ } else {
++ /* If connection host has changed update */
++ if (strcmp(ctxt->cur_host, nhost)) {
++ free(ctxt->cur_host);
++ ctxt->cur_host = nhost;
++ } else {
++ free(nhost);
++ need_base = 0;
++ }
++ }
++
++ if (!need_base)
++ return ldap;
++
++ /*
++ * If the schema isn't defined in the configuration then check for
++ * presence of a map dn with a the common schema. Then calculate the
++ * base dn for searches.
++ */
++ if (!ctxt->schema) {
++ if (!find_query_dn(ldap, ctxt)) {
++ unbind_ldap_connection(ldap, ctxt);
++ error(LOGOPT_ANY,
++ MODPREFIX "failed to find valid query dn");
++ return NULL;
++ }
++ } else {
++ const char *class = ctxt->schema->map_class;
++ const char *key = ctxt->schema->map_attr;
++ if (!get_query_dn(ldap, ctxt, class, key)) {
++ unbind_ldap_connection(ldap, ctxt);
++ error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
++ return NULL;
++ }
++ }
++
+ return ldap;
+ }
+
+@@ -769,175 +1021,17 @@ static void free_context(struct lookup_context *ctxt)
+ ldap_memfree(ctxt->qdn);
+ if (ctxt->server)
+ free(ctxt->server);
++ if (ctxt->cur_host)
++ free(ctxt->cur_host);
+ if (ctxt->base)
+ free(ctxt->base);
++ if (ctxt->sdns)
++ defaults_free_searchdns(ctxt->sdns);
+ free(ctxt);
+
+ return;
+ }
+
+-static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
+-{
+- char buf[PARSE_MAX_BUF];
+- char *query, *dn;
+- LDAPMessage *result, *e;
+- char *attrs[2];
+- int scope;
+- int rv, l;
+-
+- attrs[0] = LDAP_NO_ATTRS;
+- attrs[1] = NULL;
+-
+- if (!ctxt->mapname && !ctxt->base) {
+- error(LOGOPT_ANY, MODPREFIX "no master map to lookup");
+- return 0;
+- }
+-
+- /* Build a query string. */
+- l = strlen("(objectclass=)") + strlen(class) + 1;
+- if (ctxt->mapname)
+- l += strlen(key) + strlen(ctxt->mapname) + strlen("(&(=))");
+-
+- query = alloca(l);
+- if (query == NULL) {
+- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- crit(LOGOPT_ANY, MODPREFIX "alloca: %s", estr);
+- return NSS_STATUS_UNAVAIL;
+- }
+-
+- /*
+- * If we have a master mapname construct a query using it
+- * otherwise assume the base dn will catch it.
+- */
+- if (ctxt->mapname) {
+- if (sprintf(query, "(&(objectclass=%s)(%s=%.*s))", class,
+- key, (int) strlen(ctxt->mapname), ctxt->mapname) >= l) {
+- debug(LOGOPT_NONE,
+- MODPREFIX "error forming query string");
+- return 0;
+- }
+- scope = LDAP_SCOPE_SUBTREE;
+- } else {
+- if (sprintf(query, "(objectclass=%s)", class) >= l) {
+- debug(LOGOPT_NONE,
+- MODPREFIX "error forming query string");
+- return 0;
+- }
+- scope = LDAP_SCOPE_SUBTREE;
+- }
+- query[l] = '\0';
+-
+- rv = ldap_search_s(ldap, ctxt->base, scope, query, attrs, 0, &result);
+-
+- if ((rv != LDAP_SUCCESS) || !result) {
+- error(LOGOPT_NONE,
+- MODPREFIX "query failed for %s: %s",
+- query, ldap_err2string(rv));
+- return 0;
+- }
+-
+- e = ldap_first_entry(ldap, result);
+- if (e) {
+- dn = ldap_get_dn(ldap, e);
+- debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
+- ldap_msgfree(result);
+- } else {
+- debug(LOGOPT_NONE,
+- MODPREFIX "query succeeded, no matches for %s",
+- query);
+- ldap_msgfree(result);
+- return 0;
+- }
+-
+- ctxt->qdn = dn;
+-
+- return 1;
+-}
+-
+-static struct ldap_schema *alloc_common_schema(struct ldap_schema *s)
+-{
+- struct ldap_schema *schema;
+- char *mc, *ma, *ec, *ea, *va;
+-
+- mc = strdup(s->map_class);
+- if (!mc)
+- return NULL;
+-
+- ma = strdup(s->map_attr);
+- if (!ma) {
+- free(mc);
+- return NULL;
+- }
+-
+- ec = strdup(s->entry_class);
+- if (!ec) {
+- free(mc);
+- free(ma);
+- return NULL;
+- }
+-
+- ea = strdup(s->entry_attr);
+- if (!ea) {
+- free(mc);
+- free(ma);
+- free(ec);
+- return NULL;
+- }
+-
+- va = strdup(s->value_attr);
+- if (!va) {
+- free(mc);
+- free(ma);
+- free(ec);
+- free(ea);
+- return NULL;
+- }
+-
+- schema = malloc(sizeof(struct ldap_schema));
+- if (!schema) {
+- free(mc);
+- free(ma);
+- free(ec);
+- free(ea);
+- free(va);
+- return NULL;
+- }
+-
+- schema->map_class = mc;
+- schema->map_attr = ma;
+- schema->entry_class = ec;
+- schema->entry_attr = ea;
+- schema->value_attr = va;
+-
+- return schema;
+-}
+-
+-static int find_query_dn(LDAP *ldap, struct lookup_context *ctxt)
+-{
+- struct ldap_schema *schema;
+- unsigned int i;
+-
+- if (ctxt->schema)
+- return 0;
+-
+- for (i = 0; i < common_schema_count; i++) {
+- const char *class = common_schema[i].map_class;
+- const char *key = common_schema[i].map_attr;
+- if (get_query_dn(ldap, ctxt, class, key)) {
+- schema = alloc_common_schema(&common_schema[i]);
+- if (!schema) {
+- error(LOGOPT_ANY,
+- MODPREFIX "failed to allocate schema");
+- return 0;
+- }
+- ctxt->schema = schema;
+- return 1;
+- }
+- }
+-
+- return 0;
+-}
+-
+ /*
+ * This initializes a context (persistent non-global data) for queries to
+ * this module. Return zero if we succeed.
+@@ -994,31 +1088,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
+ free_context(ctxt);
+ return 1;
+ }
+-
+- /*
+- * Get default schema for queries.
+- * If the schema isn't defined in the configuration then check for
+- * presence of a map dn in the common schemas.
+- */
+- ctxt->schema = defaults_get_schema();
+- if (!ctxt->schema) {
+- if (!find_query_dn(ldap, ctxt)) {
+- unbind_ldap_connection(ldap, ctxt);
+- error(LOGOPT_ANY,
+- MODPREFIX "failed to find valid query dn");
+- free_context(ctxt);
+- return 1;
+- }
+- } else {
+- const char *class = ctxt->schema->map_class;
+- const char *key = ctxt->schema->map_attr;
+- if (!get_query_dn(ldap, ctxt, class, key)) {
+- unbind_ldap_connection(ldap, ctxt);
+- error(LOGOPT_ANY, MODPREFIX "failed to get query dn");
+- free_context(ctxt);
+- return 1;
+- }
+- }
+ unbind_ldap_connection(ldap, ctxt);
+
+ /* Open the parser, if we can. */
+diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
+index 85f4e34..2b1e20a 100644
+--- a/redhat/autofs.sysconfig.in
++++ b/redhat/autofs.sysconfig.in
+@@ -21,6 +21,14 @@ BROWSE_MODE="no"
+ #
+ #LOGGING="none"
+ #
++# Define base dn for map dn lookup.
++#
++# SEARCH_BASE - base dn to use for searching for map search dn.
++# Multiple entries can be given and they are checked
++# in the order they occur here.
++#
++#SEARCH_BASE=""
++#
+ # Define the LDAP schema to used for lookups
+ #
+ # If no schema is set autofs will check each of the schemas
+diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
+index 85f4e34..2b1e20a 100644
+--- a/samples/autofs.conf.default.in
++++ b/samples/autofs.conf.default.in
+@@ -21,6 +21,14 @@ BROWSE_MODE="no"
+ #
+ #LOGGING="none"
+ #
++# Define base dn for map dn lookup.
++#
++# SEARCH_BASE - base dn to use for searching for map search dn.
++# Multiple entries can be given and they are checked
++# in the order they occur here.
++#
++#SEARCH_BASE=""
++#
+ # Define the LDAP schema to used for lookups
+ #
+ # If no schema is set autofs will check each of the schemas
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index c208b31..a2a782d 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -25,6 +25,7 @@
+ - check for "*" when looking up wildcard in LDAP.
+ - fix LDAP schema discovery.
+ - add SEARCH_BASE configuration option.
++- work around segv at exit due to libxml2 tsd usage.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/aclocal.m4 b/aclocal.m4
+index d0d8346..ffeb232 100644
+--- a/aclocal.m4
++++ b/aclocal.m4
+@@ -167,6 +167,19 @@ else
+ HAVE_LIBXML=1
+ XML_LIBS=`$XML_CONFIG --libs`
+ XML_FLAGS=`$XML_CONFIG --cflags`
++ XML_VER=`$XML_CONFIG --version`
++ XML_MAJOR=`echo $XML_VER|cut -d\. -f1`
++ if test $XML_MAJOR -le 2
++ then
++ XML_MINOR=`echo $XML_VER|cut -d\. -f2`
++ if test $XML_MINOR -le 6
++ then
++ XML_REV=`echo $XML_VER|cut -d\. -f3`
++ if test $XML_REV -le 99; then
++ AC_DEFINE(LIBXML2_WORKAROUND,1, [Use libxml2 tsd usage workaround])
++ fi
++ fi
++ fi
+ fi])
+
+ dnl --------------------------------------------------------------------------
+diff --git a/configure b/configure
+index b723d74..3508224 100755
+--- a/configure
++++ b/configure
+@@ -2498,6 +2498,23 @@ echo "${ECHO_T}yes" >&6; }
+ HAVE_LIBXML=1
+ XML_LIBS=`$XML_CONFIG --libs`
+ XML_FLAGS=`$XML_CONFIG --cflags`
++ XML_VER=`$XML_CONFIG --version`
++ XML_MAJOR=`echo $XML_VER|cut -d\. -f1`
++ if test $XML_MAJOR -le 2
++ then
++ XML_MINOR=`echo $XML_VER|cut -d\. -f2`
++ if test $XML_MINOR -le 6
++ then
++ XML_REV=`echo $XML_VER|cut -d\. -f3`
++ if test $XML_REV -le 99; then
++
++cat >>confdefs.h <<\_ACEOF
++#define LIBXML2_WORKAROUND 1
++_ACEOF
++
++ fi
++ fi
++ fi
+ fi
+
+ #
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 4b6584a..aeeb7cb 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -40,6 +40,9 @@
+ #include <sys/utsname.h>
+
+ #include "automount.h"
++#ifdef LIBXML2_WORKAROUND
++#include <dlfcn.h>
++#endif
+
+ const char *program; /* Initialized with argv[0] */
+ const char *version = VERSION_STRING; /* Program version */
+@@ -1681,6 +1684,11 @@ int main(int argc, char *argv[])
+ close(start_pipefd[1]);
+ exit(1);
+ }
++
++#ifdef LIBXML2_WORKAROUND
++ void *dh = dlopen("libxml2.so", RTLD_NOW);
++#endif
++
+ if (!master_read_master(master_list, age, 0)) {
+ master_kill(master_list);
+ *pst_stat = 3;
+@@ -1702,5 +1710,9 @@ int main(int argc, char *argv[])
+ }
+ closelog();
+
++#ifdef LIBXML2_WORKAROUND
++ if (dh)
++ dlclose(dh);
++#endif
+ exit(0);
+ }
+diff --git a/include/config.h.in b/include/config.h.in
+index 942694c..9669872 100644
+--- a/include/config.h.in
++++ b/include/config.h.in
+@@ -60,6 +60,9 @@
+ /* Define to 1 if you have the <unistd.h> header file. */
+ #undef HAVE_UNISTD_H
+
++/* Use libxml2 tsd usage workaround */
++#undef LIBXML2_WORKAROUND
++
+ /* Define to the address where bug reports for this package should be sent. */
+ #undef PACKAGE_BUGREPORT
+
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index da52e71..49a9a9b 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -1998,9 +1998,6 @@ int lookup_done(void *context)
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ int rv = close_parse(ctxt->parse);
+ #ifdef WITH_SASL
+- EVP_cleanup();
+- ERR_free_strings();
+-
+ autofs_sasl_done(ctxt);
+ #endif
+ free_context(ctxt);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 93c79cf..ca290f9 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -37,6 +37,7 @@
+ - remove unused export validation code.
+ - add dynamic logging (adapted from v4 patch from Jeff Moyer).
+ - fix recursive loopback mounts (Matthias Koenig).
++- add map re-load to verbose logging.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 9ec6923..7e7d1e6 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -1278,6 +1278,8 @@ static void *do_read_master(void *arg)
+
+ defaults_read_config(1);
+
++ info(logopt, "re-reading master map %s", master->name);
++
+ status = master_read_master(master, age, readall);
+
+ master->reading = 0;
+diff --git a/daemon/state.c b/daemon/state.c
+index a2da762..cf07aac 100644
+--- a/daemon/state.c
++++ b/daemon/state.c
+@@ -376,6 +376,8 @@ static void *do_readmap(void *arg)
+
+ pthread_cleanup_push(do_readmap_cleanup, ra);
+
++ info(ap->logopt, "re-reading map for %s", ap->path);
++
+ status = lookup_nss_read_map(ap, NULL, now);
+ if (!status)
+ pthread_exit(NULL);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 74d39fd..2c815e7 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -42,6 +42,7 @@
+ - handle MTAB_NOTUPDATED status return from mount.
+ - when default master map, auto.master, is used also check for auto_master.
+ - fix schema selection in LDAP schema discovery.
++- update negative mount timeout handling.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index a12b6da..7becad5 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -58,6 +58,8 @@ const char *global_options; /* Global option, from command line */
+ static char *pid_file = NULL; /* File in which to keep pid */
+ unsigned int global_random_selection; /* use random policy when selecting
+ * which multi-mount host to mount */
++long global_negative_timeout = -1;
++
+ static int start_pipefd[2];
+ static int st_stat = 0;
+ static int *pst_stat = &st_stat;
+@@ -1671,6 +1673,8 @@ static void usage(void)
+ " -f --foreground do not fork into background\n"
+ " -r --random-multimount-selection\n"
+ " use ramdom replicated server selection\n"
++ " -n --negative-timeout n\n"
++ " set the timeout for failed key lookups.\n"
+ " -O --global-options\n"
+ " specify global mount options\n"
+ " -l --set-log-priority priority path [path,...]\n"
+@@ -1810,6 +1814,7 @@ int main(int argc, char *argv[])
+ {"define", 1, 0, 'D'},
+ {"foreground", 0, 0, 'f'},
+ {"random-multimount-selection", 0, 0, 'r'},
++ {"negative-timeout", 1, 0, 'n'},
+ {"global-options", 1, 0, 'O'},
+ {"version", 0, 0, 'V'},
+ {"set-log-priority", 1, 0, 'l'},
+@@ -1833,7 +1838,7 @@ int main(int argc, char *argv[])
+ foreground = 0;
+
+ opterr = 0;
+- while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:", long_options, NULL)) != EOF) {
++ while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:", long_options, NULL)) != EOF) {
+ switch (opt) {
+ case 'h':
+ usage();
+@@ -1871,6 +1876,10 @@ int main(int argc, char *argv[])
+ global_random_selection = 1;
+ break;
+
++ case 'n':
++ global_negative_timeout = getnumopt(optarg, opt);
++ break;
++
+ case 'O':
+ if (!have_global_options) {
+ global_options = strdup(optarg);
+diff --git a/include/automount.h b/include/automount.h
+index b0d1a9c..4887da6 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -442,6 +442,7 @@ struct autofs_point {
+ unsigned int type; /* Type of map direct or indirect */
+ time_t exp_timeout; /* Timeout for expiring mounts */
+ time_t exp_runfreq; /* Frequency for polling for timeouts */
++ time_t negative_timeout; /* timeout in secs for failed mounts */
+ unsigned ghost; /* Enable/disable gohsted directories */
+ unsigned logopt; /* Per map logging */
+ pthread_t exp_thread; /* Thread that is expiring */
+diff --git a/include/defaults.h b/include/defaults.h
+index e296478..6e4f52a 100644
+--- a/include/defaults.h
++++ b/include/defaults.h
+@@ -22,9 +22,10 @@
+
+ #define DEFAULT_MASTER_MAP_NAME "auto.master"
+
+-#define DEFAULT_TIMEOUT 600
+-#define DEFAULT_BROWSE_MODE 1
+-#define DEFAULT_LOGGING 0
++#define DEFAULT_TIMEOUT 600
++#define DEFAULT_NEGATIVE_TIMEOUT 60
++#define DEFAULT_BROWSE_MODE 1
++#define DEFAULT_LOGGING 0
+
+ #define DEFAULT_LDAP_TIMEOUT -1
+ #define DEFAULT_LDAP_NETWORK_TIMEOUT 8
+@@ -45,6 +46,7 @@ unsigned int defaults_read_config(unsigned int);
+ const char *defaults_get_master_map(void);
+ int defaults_master_set(void);
+ unsigned int defaults_get_timeout(void);
++unsigned int defaults_get_negative_timeout(void);
+ unsigned int defaults_get_browse_mode(void);
+ unsigned int defaults_get_logging(void);
+ const char *defaults_get_ldap_server(void);
+diff --git a/lib/defaults.c b/lib/defaults.c
+index f494103..8149549 100644
+--- a/lib/defaults.c
++++ b/lib/defaults.c
+@@ -28,6 +28,7 @@
+ #define ENV_NAME_MASTER_MAP "MASTER_MAP_NAME"
+
+ #define ENV_NAME_TIMEOUT "TIMEOUT"
++#define ENV_NAME_NEGATIVE_TIMEOUT "NEGATIVE_TIMEOUT"
+ #define ENV_NAME_BROWSE_MODE "BROWSE_MODE"
+ #define ENV_NAME_LOGGING "LOGGING"
+
+@@ -308,6 +309,7 @@ unsigned int defaults_read_config(unsigned int to_syslog)
+
+ if (check_set_config_value(key, ENV_NAME_MASTER_MAP, value, to_syslog) ||
+ check_set_config_value(key, ENV_NAME_TIMEOUT, value, to_syslog) ||
++ check_set_config_value(key, ENV_NAME_NEGATIVE_TIMEOUT, value, to_syslog) ||
+ check_set_config_value(key, ENV_NAME_BROWSE_MODE, value, to_syslog) ||
+ check_set_config_value(key, ENV_NAME_LOGGING, value, to_syslog) ||
+ check_set_config_value(key, ENV_LDAP_TIMEOUT, value, to_syslog) ||
+@@ -370,6 +372,17 @@ unsigned int defaults_get_timeout(void)
+ return (unsigned int) timeout;
+ }
+
++unsigned int defaults_get_negative_timeout(void)
++{
++ long n_timeout;
++
++ n_timeout = get_env_number(ENV_NAME_NEGATIVE_TIMEOUT);
++ if (n_timeout <= 0)
++ n_timeout = DEFAULT_NEGATIVE_TIMEOUT;
++
++ return (unsigned int) n_timeout;
++}
++
+ unsigned int defaults_get_browse_mode(void)
+ {
+ int res;
+diff --git a/lib/master.c b/lib/master.c
+index 2188bca..c001d20 100644
+--- a/lib/master.c
++++ b/lib/master.c
+@@ -30,6 +30,8 @@
+ /* The root of the map entry tree */
+ struct master *master_list = NULL;
+
++extern long global_negative_timeout;
++
+ /* Attribute to create detached thread */
+ extern pthread_attr_t thread_attr;
+
+@@ -68,6 +70,14 @@ int master_add_autofs_point(struct master_mapent *entry,
+ ap->exp_thread = 0;
+ ap->readmap_thread = 0;
+ ap->exp_timeout = timeout;
++ /*
++ * Program command line option overrides config.
++ * We can't use 0 negative timeout so use default.
++ */
++ if (global_negative_timeout <= 0)
++ ap->negative_timeout = defaults_get_negative_timeout();
++ else
++ ap->negative_timeout = global_negative_timeout;
+ ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
+ ap->ghost = ghost;
+
+diff --git a/lib/master_parse.y b/lib/master_parse.y
+index a767f9e..b450122 100644
+--- a/lib/master_parse.y
++++ b/lib/master_parse.y
+@@ -55,6 +55,7 @@ static char *path;
+ static char *type;
+ static char *format;
+ static long timeout;
++static long negative_timeout;
+ static unsigned ghost;
+ extern unsigned global_random_selection;
+ static unsigned random_selection;
+@@ -95,7 +96,8 @@ static int master_fprintf(FILE *, char *, ...);
+
+ %token COMMENT
+ %token MAP
+-%token OPT_TIMEOUT OPT_NOGHOST OPT_GHOST OPT_VERBOSE OPT_DEBUG OPT_RANDOM
++%token OPT_TIMEOUT OPT_NTIMEOUT OPT_NOGHOST OPT_GHOST OPT_VERBOSE
++%token OPT_DEBUG OPT_RANDOM
+ %token COLON COMMA NL DDASH
+ %type <strtype> map
+ %type <strtype> options
+@@ -542,6 +544,7 @@ option: daemon_option
+ ;
+
+ daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; }
++ | OPT_NTIMEOUT NUMBER { negative_timeout = $2; }
+ | OPT_NOGHOST { ghost = 0; }
+ | OPT_GHOST { ghost = 1; }
+ | OPT_VERBOSE { verbose = 1; }
+@@ -603,6 +606,7 @@ static void local_init_vars(void)
+ verbose = 0;
+ debug = 0;
+ timeout = -1;
++ negative_timeout = 0;
+ ghost = defaults_get_browse_mode();
+ random_selection = global_random_selection;
+ tmp_argv = NULL;
+@@ -793,6 +797,8 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ }
+ }
+ entry->ap->random_selection = random_selection;
++ if (negative_timeout)
++ entry->ap->negative_timeout = negative_timeout;
+
+ /*
+ source = master_find_map_source(entry, type, format,
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 36aa785..d908047 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -118,6 +118,7 @@ MTYPE ((file|program|yp|nis|nisplus|ldap|ldaps|hesiod|userdir)(,(sun|hesiod))?(
+
+
+ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
++OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|--negative-timeout{OPTWS}|--negative-timeout{OPTWS}={OPTWS})
+
+ %%
+
+@@ -321,6 +322,8 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+
+ {OPTTOUT}/{NUMBER} { return(OPT_TIMEOUT); }
+
++ {OPTNTOUT}/{NUMBER} { return(OPT_NTIMEOUT); }
++
+ {NUMBER} {
+ master_lval.longtype = atol(master_text);
+ return(NUMBER);
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index 68447e0..d488960 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -152,6 +152,11 @@ Enables the use of ramdom selection when choosing a host from a
+ list of replicated servers. This option is applied to this mount
+ only, overriding the global setting that may be specified on the
+ command line.
++.TP
++.I "\-n, \-\-negative\-timeout <seconds>"
++Set the timeout for caching failed key lookups. This option can be
++used to override the global default given either on the command line
++or in the configuration.
+ .SH GENERAL SYSTEM DEFAULTS CONFIGURATION
+ .P
+ The default value of several general settings may be changed in the
+@@ -164,6 +169,11 @@ They are:
+ .B TIMEOUT
+ sets the default mount timeout (program default 600).
+ .TP
++.B NEGATIVE_TIMEOUT
++Set the default timeout for caching failed key lookups (program default
++60). If the equivalent command line option is given it will override this
++setting.
++.TP
+ .B BROWSE_MODE
+ Maps are browsable by default (program default "yes").
+ .TP
+diff --git a/man/automount.8 b/man/automount.8
+index 5cd63c7..59ad50e 100644
+--- a/man/automount.8
++++ b/man/automount.8
+@@ -34,6 +34,9 @@ Set the global minimum timeout, in seconds, until directories
+ are unmounted. The default is 10 minutes. Setting the timeout
+ to zero disables umounts completely.
+ .TP
++.I "\-n <seconds>, \-\-negative\-timeout <seconds>"
++Set the default timeout for caching failed key lookups. The default is 60 seconds.
++.TP
+ .I "\-v, \-\-verbose"
+ Enables logging of general status and progress messages for all
+ autofs managed mounts.
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index c093415..1007de4 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -1126,7 +1126,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ rv = cache_update(mc, source, key, NULL, now);
+ if (rv != CHE_FAIL) {
+ me = cache_lookup_distinct(mc, key);
+- me->status = now + NEGATIVE_TIMEOUT;
++ me->status = now + ap->negative_timeout;
+ }
+ cache_unlock(mc);
+ }
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index d746e42..1ef420e 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -138,7 +138,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, name);
+- if (!me) {
++ if (me && me->status >= time(NULL)) {
++ cache_unlock(mc);
++ return NSS_STATUS_NOTFOUND;
++ } else if (!me) {
+ cache_unlock(mc);
+ /*
+ * We haven't read the list of hosts into the
+@@ -192,10 +195,22 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ ret = ctxt->parse->parse_mount(ap, name, name_len,
+ mapent, ctxt->parse->context);
+
+- if (!ret)
+- return NSS_STATUS_SUCCESS;
+-
+- return NSS_STATUS_TRYAGAIN;
++ if (ret) {
++ time_t now = time(NULL);
++ int rv = CHE_OK;
++
++ cache_writelock(mc);
++ me = cache_lookup_distinct(mc, name);
++ if (!me)
++ rv = cache_update(mc, source, name, NULL, now);
++ if (rv != CHE_FAIL) {
++ me = cache_lookup_distinct(mc, name);
++ me->status = now + ap->negative_timeout;
++ }
++ cache_unlock(mc);
++ return NSS_STATUS_TRYAGAIN;
++ }
++ return NSS_STATUS_SUCCESS;
+ }
+ done:
+ /*
+@@ -267,8 +282,21 @@ done:
+ mapent, ctxt->parse->context);
+ free(mapent);
+
+- if (ret)
++ if (ret) {
++ time_t now = time(NULL);
++ int rv = CHE_OK;
++
++ cache_writelock(mc);
++ me = cache_lookup_distinct(mc, name);
++ if (!me)
++ rv = cache_update(mc, source, name, NULL, now);
++ if (rv != CHE_FAIL) {
++ me = cache_lookup_distinct(mc, name);
++ me->status = now + ap->negative_timeout;
++ }
++ cache_unlock(mc);
+ return NSS_STATUS_TRYAGAIN;
++ }
+
+ return NSS_STATUS_SUCCESS;
+ }
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 8719af9..4dea3b2 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -2125,7 +2125,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ rv = cache_update(mc, source, key, NULL, now);
+ if (rv != CHE_FAIL) {
+ me = cache_lookup_distinct(mc, key);
+- me->status = now + NEGATIVE_TIMEOUT;
++ me->status = now + ap->negative_timeout;
+ }
+ cache_unlock(mc);
+ }
+diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
+index bcdaeeb..e948c14 100644
+--- a/modules/lookup_nisplus.c
++++ b/modules/lookup_nisplus.c
+@@ -547,7 +547,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ rv = cache_update(mc, source, key, NULL, now);
+ if (rv != CHE_FAIL) {
+ me = cache_lookup_distinct(mc, key);
+- me->status = time(NULL) + NEGATIVE_TIMEOUT;
++ me->status = time(NULL) + ap->negative_timeout;
+ }
+ cache_unlock(mc);
+ }
+diff --git a/modules/lookup_program.c b/modules/lookup_program.c
+index e28168e..7c266d6 100644
+--- a/modules/lookup_program.c
++++ b/modules/lookup_program.c
+@@ -134,7 +134,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ /* Catch installed direct offset triggers */
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, name);
+- if (!me) {
++ if (me && me->status >= time(NULL)) {
++ cache_unlock(mc);
++ return NSS_STATUS_NOTFOUND;
++ } else if (!me) {
+ cache_unlock(mc);
+ /*
+ * If there's a '/' in the name and the offset is not in
+@@ -147,15 +150,33 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ }
+ } else {
+ cache_unlock(mc);
++
+ /* Otherwise we found a valid offset so try mount it */
+ debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent);
+
+- master_source_current_wait(ap->entry);
+- ap->entry->current = source;
+-
+- ret = ctxt->parse->parse_mount(ap, name, name_len,
+- me->mapent, ctxt->parse->context);
+- goto out_free;
++ /*
++ * If this is a request for an offset mount (whose entry
++ * must be present in the cache to be valid) or the entry
++ * is newer than the negative timeout value then just
++ * try and mount it. Otherwise try and remove it and
++ * proceed with the program map lookup.
++ */
++ if (strchr(name, '/') ||
++ me->age + ap->negative_timeout > time(NULL)) {
++ master_source_current_wait(ap->entry);
++ ap->entry->current = source;
++ ret = ctxt->parse->parse_mount(ap, name,
++ name_len, me->mapent, ctxt->parse->context);
++ goto out_free;
++ } else {
++ if (me->multi) {
++ warn(ap->logopt, MODPREFIX
++ "unexpected lookup for active multi-mount"
++ " key %s, returning fail", name);
++ return NSS_STATUS_UNAVAIL;
++ }
++ cache_delete(mc, name);
++ }
+ }
+
+ mapent = (char *) malloc(MAPENT_MAX_LEN + 1);
+@@ -356,8 +377,21 @@ out_free:
+ if (mapent)
+ free(mapent);
+
+- if (ret)
++ if (ret) {
++ time_t now = time(NULL);
++ int rv = CHE_OK;
++
++ cache_writelock(mc);
++ me = cache_lookup_distinct(mc, name);
++ if (!me)
++ rv = cache_update(mc, source, name, NULL, now);
++ if (rv != CHE_FAIL) {
++ me = cache_lookup_distinct(mc, name);
++ me->status = now + ap->negative_timeout;
++ }
++ cache_unlock(mc);
+ return NSS_STATUS_UNAVAIL;
++ }
+
+ return NSS_STATUS_SUCCESS;
+ }
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index 7ba6940..6c20145 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -639,7 +639,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ rv = cache_update(mc, source, key, NULL, now);
+ if (rv != CHE_FAIL) {
+ me = cache_lookup_distinct(mc, key);
+- me->status = now + NEGATIVE_TIMEOUT;
++ me->status = now + ap->negative_timeout;
+ }
+ cache_unlock(mc);
+ }
+diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
+index f01ee5f..636763a 100644
+--- a/redhat/autofs.sysconfig.in
++++ b/redhat/autofs.sysconfig.in
+@@ -9,6 +9,11 @@
+ #
+ TIMEOUT=300
+ #
++# NEGATIVE_TIMEOUT - set the default negative timeout for
++# failed mount attempts (default 60).
++#
++#NEGATIVE_TIMEOUT=60
++#
+ # BROWSE_MODE - maps are browsable by default.
+ #
+ BROWSE_MODE="no"
+diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
+index 028341c..086ba4f 100644
+--- a/samples/autofs.conf.default.in
++++ b/samples/autofs.conf.default.in
+@@ -9,6 +9,11 @@
+ #
+ TIMEOUT=300
+ #
++# NEGATIVE_TIMEOUT - set the default negative timeout for
++# failed mount attempts (default 60).
++#
++#NEGATIVE_TIMEOUT=60
++#
+ # BROWSE_MODE - maps are browsable by default.
+ #
+ BROWSE_MODE="no"
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index fcfbe62..c29d577 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -51,6 +51,7 @@
+ - improve handling of server not available.
+ - fix LDAP_URI server selection.
+ - add authentication option for using an external credential cache.
++- expand support for the "%" hack.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 13fbff7..65f1fda 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -1411,6 +1411,140 @@ next:
+ return NSS_STATUS_SUCCESS;
+ }
+
++/*
++ * Deal with encode and decode of % hack.
++ * Return
++ * 0 => % hack not present.
++ * -1 => syntax error or alloc fail.
++ * 1 transofrmed value returned.
++ */
++static int decode_percent_hack(const char *name, char **key)
++{
++ const char *tmp;
++ char *ptr, *new;
++
++ if (!key)
++ return -1;
++
++ *key = NULL;
++
++ tmp = name;
++ while (*tmp && *tmp != '%' && *tmp != '[' && *tmp != ']')
++ tmp++;
++ if (!*tmp)
++ return 0;
++
++ tmp = name;
++ while (*tmp) {
++ if (*tmp == '%') {
++ tmp++;
++ if (!*tmp)
++ return -1;
++ if (*tmp != '[')
++ continue;
++ tmp++;
++ while (*tmp && *tmp != ']') {
++ if (*tmp == '%')
++ tmp++;
++ tmp++;
++ }
++ if (!tmp)
++ return -1;
++ }
++ tmp++;
++ }
++
++ new = malloc(strlen(name) + 1);
++ if (!new)
++ return -1;
++
++ ptr = new;
++ tmp = name;
++ while (*tmp) {
++ if (*tmp == '%' || *tmp == '[' || *tmp == ']') {
++ tmp++;
++ if (*tmp && *tmp != '%')
++ continue;
++ }
++ *ptr++ = *tmp++;
++ }
++ *ptr = '\0';
++
++ *key = new;
++
++ return strlen(new);
++}
++
++static int encode_percent_hack(const char *name, char **key, unsigned int use_class)
++{
++ const char *tmp;
++ unsigned int len = 0;
++ char *ptr, *new;
++
++ if (!key)
++ return -1;
++
++ *key = NULL;
++
++ tmp = name;
++ while (*tmp) {
++ if (*tmp == '%')
++ len++;
++ else if (isupper(*tmp)) {
++ tmp++;
++ len++;
++ if (!use_class)
++ len++;
++ else {
++ if (*tmp && isupper(*tmp))
++ len += 2;
++ else
++ return 0;
++ while (*tmp && isupper(*tmp)) {
++ len++;
++ tmp++;
++ }
++ }
++ continue;
++ }
++ len++;
++ tmp++;
++ }
++ if (len == strlen(name))
++ return 0;
++
++ new = malloc(len + 1);
++ if (!new)
++ return -1;
++
++ ptr = new;
++ tmp = name;
++ while (*tmp) {
++ if (*tmp == '%')
++ *ptr++ = '%';
++ else if (isupper(*tmp)) {
++ char next = *tmp++;
++ *ptr++ = '%';
++ if (*tmp && (!isupper(*tmp) || !use_class))
++ *ptr++ = next;
++ else {
++ *ptr++ = '[';
++ *ptr++ = next;
++ while (*tmp && isupper(*tmp))
++ *ptr++ = *tmp++;
++ *ptr++ = ']';
++ }
++ continue;
++ }
++ *ptr++ = *tmp++;
++ }
++ *ptr = '\0';
++
++ *key = new;
++
++ return strlen(new);
++}
++
+ static int read_one_map(struct autofs_point *ap,
+ struct lookup_context *ctxt,
+ time_t age, int *result_ldap)
+@@ -1518,7 +1652,7 @@ static int read_one_map(struct autofs_point *ap,
+ * people using older schemas that allow '*' as a key
+ * value. Another case where there can be multiple key
+ * values is when people have used the "%" hack to specify
+- * case matching ctriteria in a caase insensitive attribute.
++ * case matching ctriteria in a case insensitive attribute.
+ */
+ count = ldap_count_values_len(bvKey);
+ if (count > 1) {
+@@ -1647,9 +1781,30 @@ static int read_one_map(struct autofs_point *ap,
+ *k_val = '*';
+ }
+
+- s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
+- if (!s_key)
+- goto next;
++ if (strcasecmp(class, "nisObject")) {
++ s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
++ if (!s_key)
++ goto next;
++ } else {
++ char *dec_key;
++ int dec_len = decode_percent_hack(k_val, &dec_key);
++
++ if (dec_len < 0) {
++ crit(ap->logopt,
++ "could not use percent hack to decode key %s",
++ k_val);
++ goto next;
++ }
++
++ if (dec_len == 0)
++ s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
++ else {
++ s_key = sanitize_path(dec_key, dec_len, ap->type, ap->logopt);
++ free(dec_key);
++ }
++ if (!s_key)
++ goto next;
++ }
+
+ cache_writelock(mc);
+ cache_update(mc, source, s_key, mapent, age);
+@@ -1712,6 +1867,8 @@ static int lookup_one(struct autofs_point *ap,
+ char *query;
+ LDAPMessage *result, *e;
+ char *class, *info, *entry;
++ char *enc_key1, *enc_key2;
++ int enc_len1 = 0, enc_len2 = 0;
+ struct berval **bvKey;
+ struct berval **bvValues;
+ char *attrs[3];
+@@ -1742,14 +1899,38 @@ static int lookup_one(struct autofs_point *ap,
+
+ if (*qKey == '*' && qKey_len == 1)
+ *qKey = '/';
++ else if (!strcasecmp(class, "nisObject")) {
++ enc_len1 = encode_percent_hack(qKey, &enc_key1, 0);
++ if (enc_len1 < 0) {
++ crit(ap->logopt,
++ "could not use percent hack encode key %s",
++ qKey);
++ return CHE_FAIL;
++ }
++ if (enc_len1 != 0) {
++ enc_len2 = encode_percent_hack(qKey, &enc_key2, 1);
++ if (enc_len2 < 0) {
++ crit(ap->logopt,
++ "could not use percent hack encode key %s",
++ qKey);
++ return CHE_FAIL;
++ }
++ }
++ }
+
+ /* Build a query string. */
+ l = strlen(class) + 3*strlen(entry) + strlen(qKey) + 35;
++ if (enc_len1)
++ l += 2*strlen(entry) + enc_len1 + enc_len2 + 6;
+
+ query = alloca(l);
+ if (query == NULL) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ crit(ap->logopt, MODPREFIX "malloc: %s", estr);
++ if (enc_len1) {
++ free(enc_key1);
++ free(enc_key2);
++ }
+ return CHE_FAIL;
+ }
+
+@@ -1757,8 +1938,27 @@ static int lookup_one(struct autofs_point *ap,
+ * Look for an entry in class under ctxt-base
+ * whose entry is equal to qKey.
+ */
+- ql = sprintf(query,
+- "(&(objectclass=%s)(|(%s=%s)(%s=/)(%s=\\2A)))", class, entry, qKey, entry, entry);
++ if (!enc_len1) {
++ ql = sprintf(query,
++ "(&(objectclass=%s)(|(%s=%s)(%s=/)(%s=\\2A)))",
++ class, entry, qKey, entry, entry);
++ } else {
++ if (enc_len2) {
++ ql = sprintf(query,
++ "(&(objectclass=%s)"
++ "(|(%s=%s)(%s=%s)(%s=%s)(%s=/)(%s=\\2A)))",
++ class, entry, qKey,
++ entry, enc_key1, entry, enc_key2, entry, entry);
++ free(enc_key1);
++ free(enc_key2);
++ } else {
++ ql = sprintf(query,
++ "(&(objectclass=%s)"
++ "(|(%s=%s)(%s=%s)(%s=/)(%s=\\2A)))",
++ class, entry, qKey, entry, enc_key1, entry, entry);
++ free(enc_key1);
++ }
++ }
+ if (ql >= l) {
+ error(ap->logopt,
+ MODPREFIX "error forming query string");
+@@ -1934,9 +2134,30 @@ static int lookup_one(struct autofs_point *ap,
+ goto next;
+ }
+
+- s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
+- if (!s_key)
+- goto next;
++ if (strcasecmp(class, "nisObject")) {
++ s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
++ if (!s_key)
++ goto next;
++ } else {
++ char *dec_key;
++ int dec_len = decode_percent_hack(k_val, &dec_key);
++
++ if (dec_len < 0) {
++ crit(ap->logopt,
++ "could not use percent hack to decode key %s",
++ k_val);
++ goto next;
++ }
++
++ if (dec_len == 0)
++ s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
++ else {
++ s_key = sanitize_path(dec_key, dec_len, ap->type, ap->logopt);
++ free(dec_key);
++ }
++ if (!s_key)
++ goto next;
++ }
+
+ cache_writelock(mc);
+ ret = cache_update(mc, source, s_key, mapent, age);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 4aa384b..09b0541 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -55,6 +55,7 @@
+ - fix to quoting for exports gathered by hosts map.
+ - use mount option "nosuid" for "-hosts" map unless "suid" is explicily specified.
+ - second attempt fixing quoting for exports gathered by hosts map.
++- quell annoying "cannot open mount module" message.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/mount.c b/daemon/mount.c
+index 59f8f44..494ede1 100644
+--- a/daemon/mount.c
++++ b/daemon/mount.c
+@@ -38,14 +38,21 @@ int do_mount(struct autofs_point *ap, const char *root, const char *name, int na
+ char **ngp;
+ int rv;
+
+- mod = open_mount(modstr = fstype, ERR_PREFIX);
++ /* Initially look for a mount module but don't issue an error on fail */
++ mod = open_mount(modstr = fstype, NULL);
+ if (!mod) {
+ for (ngp = not_generic; *ngp; ngp++) {
+ if (!strcmp(fstype, *ngp))
+ break;
+ }
++ /*
++ * If there's not a known mount module use the generic module,
++ * otherwise redo the fs mount module with error reporting
++ */
+ if (!*ngp)
+ mod = open_mount(modstr = "generic", ERR_PREFIX);
++ else
++ mod = open_mount(modstr = fstype, ERR_PREFIX);
+ if (!mod) {
+ error(ap->logopt,
+ "cannot find mount method for filesystem %s",
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 0fcdfd4..4aa384b 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -54,6 +54,7 @@
+ - expand support for the "%" hack.
+ - fix to quoting for exports gathered by hosts map.
+ - use mount option "nosuid" for "-hosts" map unless "suid" is explicily specified.
++- second attempt fixing quoting for exports gathered by hosts map.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index 70b13a7..1ef420e 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -179,14 +179,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ if (*name == '/') {
+ pthread_cleanup_push(cache_lock_cleanup, mc);
+ mapent_len = strlen(me->mapent);
+- mapent = alloca(mapent_len + 3);
+- if (mapent) {
+- /* Add quotes to keep the parser happy */
+- mapent[0] = '"';
+- strcpy(mapent + 1, me->mapent);
+- mapent[mapent_len + 1] = '"';
+- mapent[mapent_len + 2] = '\0';
+- }
++ mapent = alloca(mapent_len + 1);
++ if (mapent)
++ strcpy(mapent, me->mapent);
+ pthread_cleanup_pop(0);
+ }
+ cache_unlock(mc);
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 9a97329..a97a7aa 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -878,7 +878,7 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char *
+ }
+
+ if (!validate_location(loc)) {
+- warn(logopt, MODPREFIX "invalid location");
++ warn(logopt, MODPREFIX "invalid location %s", loc);
+ free(myoptions);
+ free(loc);
+ return 0;
+@@ -913,7 +913,7 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char *
+
+ if (!validate_location(ent_chunk)) {
+ warn(logopt,
+- MODPREFIX "invalid location %s", ent);
++ MODPREFIX "invalid location %s", ent_chunk);
+ free(ent_chunk);
+ free(myoptions);
+ free(loc);
+@@ -1344,6 +1344,23 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ int loclen;
+ int l;
+
++ /*
++ * If this is an offset belonging to a multi-mount entry
++ * it's already been parsed (above) and any option string
++ * has already been stripped so just use the remainder.
++ */
++ if (*name == '/' &&
++ (me = cache_lookup_distinct(mc, name)) && me->multi) {
++ loc = strdup(p);
++ if (!loc) {
++ free(options);
++ warn(ap->logopt, MODPREFIX "out of memory");
++ return 1;
++ }
++ loclen = strlen(p);
++ goto mount_it;
++ }
++
+ l = chunklen(p, check_colon(p));
+ loc = dequote(p, l, ap->logopt);
+ if (!loc) {
+@@ -1361,9 +1378,9 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ }
+
+ if (!validate_location(loc)) {
++ warn(ap->logopt, MODPREFIX "invalid location %s", loc);
+ free(loc);
+ free(options);
+- warn(ap->logopt, MODPREFIX "invalid location");
+ return 1;
+ }
+
+@@ -1387,10 +1404,11 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ }
+
+ if (!validate_location(ent)) {
++ warn(ap->logopt,
++ MODPREFIX "invalid location %s", loc);
+ free(ent);
+ free(loc);
+ free(options);
+- warn(ap->logopt, MODPREFIX "invalid location");
+ return 1;
+ }
+
+@@ -1424,7 +1442,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ MODPREFIX "entry %s is empty!", name);
+ return 1;
+ }
+-
++mount_it:
+ debug(ap->logopt,
+ MODPREFIX "core of entry: options=%s, loc=%.*s",
+ options, loclen, loc);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index c29d577..c486a7b 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -52,6 +52,7 @@
+ - fix LDAP_URI server selection.
+ - add authentication option for using an external credential cache.
+ - expand support for the "%" hack.
++- fix to quoting for exports gathered by hosts map.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index 1ef420e..70b13a7 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -179,9 +179,14 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ if (*name == '/') {
+ pthread_cleanup_push(cache_lock_cleanup, mc);
+ mapent_len = strlen(me->mapent);
+- mapent = alloca(mapent_len + 1);
+- if (mapent)
+- strcpy(mapent, me->mapent);
++ mapent = alloca(mapent_len + 3);
++ if (mapent) {
++ /* Add quotes to keep the parser happy */
++ mapent[0] = '"';
++ strcpy(mapent + 1, me->mapent);
++ mapent[mapent_len + 1] = '"';
++ mapent[mapent_len + 2] = '\0';
++ }
+ pthread_cleanup_pop(0);
+ }
+ cache_unlock(mc);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 2ce58b4..903e619 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -7,6 +7,7 @@
+ - change random multiple server selection option name to be consistent
+ with existing downstream version 4 naming.
+ - fix mount point directory creation for bind mounts.
++- add quoting for exports gathered by hosts map.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index a9a4c75..1f8fa15 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -215,7 +215,7 @@ done:
+ if (mapent) {
+ int len = strlen(mapent) + 1;
+
+- len += strlen(name) + 2*strlen(exp->ex_dir) + 3;
++ len += strlen(name) + 2*(strlen(exp->ex_dir) + 2) + 3;
+ mapent = realloc(mapent, len);
+ if (!mapent) {
+ char *estr;
+@@ -224,10 +224,11 @@ done:
+ rpc_exports_free(exp);
+ return NSS_STATUS_UNAVAIL;
+ }
+- strcat(mapent, " ");
++ strcat(mapent, " \"");
+ strcat(mapent, exp->ex_dir);
++ strcat(mapent, "\"");
+ } else {
+- int len = 2*strlen(exp->ex_dir) + strlen(name) + 3;
++ int len = 2*(strlen(exp->ex_dir) + 2) + strlen(name) + 3;
+
+ mapent = malloc(len);
+ if (!mapent) {
+@@ -237,12 +238,15 @@ done:
+ rpc_exports_free(exp);
+ return NSS_STATUS_UNAVAIL;
+ }
+- strcpy(mapent, exp->ex_dir);
++ strcpy(mapent, "\"");
++ strcat(mapent, exp->ex_dir);
++ strcat(mapent, "\"");
+ }
+- strcat(mapent, " ");
++ strcat(mapent, " \"");
+ strcat(mapent, name);
+ strcat(mapent, ":");
+ strcat(mapent, exp->ex_dir);
++ strcat(mapent, "\"");
+
+ exp = exp->ex_next;
+ }
+@@ -260,13 +264,9 @@ done:
+ cache_update(mc, source, name, mapent, now);
+ cache_unlock(mc);
+
+- debug(LOGOPT_ANY, "source wait");
+-
+ master_source_current_wait(ap->entry);
+ ap->entry->current = source;
+
+- debug(LOGOPT_ANY, "do parse_mount");
+-
+ ret = ctxt->parse->parse_mount(ap, name, name_len,
+ mapent, ctxt->parse->context);
+ free(mapent);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index bc4d8fd..1bf4b27 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -9,6 +9,7 @@
+ - fix mount point directory creation for bind mounts.
+ - add quoting for exports gathered by hosts map.
+ - fix wait time resolution in alarm and state queue handlers.
++- fix handling of quoted slash alone.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/parse_subs.c b/lib/parse_subs.c
+index ad19f34..3627f44 100644
+--- a/lib/parse_subs.c
++++ b/lib/parse_subs.c
+@@ -297,7 +297,8 @@ char *sanitize_path(const char *path, int origlen, unsigned int type, unsigned i
+ return NULL;
+ }
+
+- if (origlen > 1 && *(cp - 1) == '/')
++ /* Remove trailing / but watch out for a quoted / alone */
++ if (strlen(cp) > 1 && origlen > 1 && *(cp - 1) == '/')
+ *(cp - 1) = '\0';
+
+ return s_path;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index c36017a..0e9dc51 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -20,6 +20,7 @@
+ - fix don't fail on empty master map.
+ - if there's no "automount" entry in nsswitch.conf use "files" source.
+ - add LDAP schema discovery if no schema is configured.
++- add random selection as a master map entry option.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 7b79f02..4b6584a 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -49,9 +49,9 @@ const char *confdir = AUTOFS_CONF_DIR; /* Location of autofs config file */
+
+ const char *global_options; /* Global option, from command line */
+
+-static char *pid_file = NULL; /* File in which to keep pid */
+-unsigned int random_selection; /* use random policy when selecting
+- * which multi-mount host to mount */
++static char *pid_file = NULL; /* File in which to keep pid */
++unsigned int global_random_selection; /* use random policy when selecting
++ * which multi-mount host to mount */
+ static int start_pipefd[2];
+ static int st_stat = 0;
+ static int *pst_stat = &st_stat;
+@@ -1490,7 +1490,7 @@ int main(int argc, char *argv[])
+ timeout = defaults_get_timeout();
+ ghost = defaults_get_browse_mode();
+ logging = defaults_get_logging();
+- random_selection = 0;
++ global_random_selection = 0;
+ global_options = NULL;
+ have_global_options = 0;
+ foreground = 0;
+@@ -1531,7 +1531,7 @@ int main(int argc, char *argv[])
+ exit(0);
+
+ case 'r':
+- random_selection = 1;
++ global_random_selection = 1;
+ break;
+
+ case 'O':
+diff --git a/include/automount.h b/include/automount.h
+index d9e4ecd..d55ba5c 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -448,6 +448,8 @@ struct autofs_point {
+ enum states state; /* Current state */
+ int state_pipe[2]; /* State change router pipe */
+ unsigned dir_created; /* Directory created for this mount? */
++ unsigned random_selection; /* Use random policy when selecting a
++ * host from which to mount */
+ struct autofs_point *parent; /* Owner of mounts list for submount */
+ pthread_mutex_t mounts_mutex; /* Protect mount lists */
+ pthread_cond_t mounts_cond; /* Submounts condition variable */
+diff --git a/include/replicated.h b/include/replicated.h
+index c77cda6..3afe9f7 100644
+--- a/include/replicated.h
++++ b/include/replicated.h
+@@ -63,7 +63,7 @@ struct host {
+ void seed_random(void);
+ void free_host_list(struct host **);
+ int parse_location(struct host **, const char *);
+-int prune_host_list(struct host **, unsigned int, const char *);
++int prune_host_list(struct host **, unsigned int, const char *, unsigned int);
+ void dump_host_list(struct host *);
+
+ #endif
+diff --git a/lib/master_parse.y b/lib/master_parse.y
+index ab2895d..70b48be 100644
+--- a/lib/master_parse.y
++++ b/lib/master_parse.y
+@@ -56,6 +56,8 @@ static char *type;
+ static char *format;
+ static long timeout;
+ static unsigned ghost;
++extern unsigned global_random_selection;
++static unsigned random_selection;
+ static char **tmp_argv;
+ static int tmp_argc;
+ static char **local_argv;
+@@ -93,7 +95,7 @@ static int master_fprintf(FILE *, char *, ...);
+
+ %token COMMENT
+ %token MAP
+-%token OPT_TIMEOUT OPT_NOGHOST OPT_GHOST OPT_VERBOSE OPT_DEBUG
++%token OPT_TIMEOUT OPT_NOGHOST OPT_GHOST OPT_VERBOSE OPT_DEBUG OPT_RANDOM
+ %token COLON COMMA NL DDASH
+ %type <strtype> map
+ %type <strtype> options
+@@ -174,6 +176,7 @@ line:
+ | PATH COLON { master_notify($1); YYABORT; }
+ | PATH OPTION { master_notify($2); YYABORT; }
+ | PATH NILL { master_notify($2); YYABORT; }
++ | PATH OPT_RANDOM { master_notify($1); YYABORT; }
+ | PATH OPT_DEBUG { master_notify($1); YYABORT; }
+ | PATH OPT_TIMEOUT { master_notify($1); YYABORT; }
+ | PATH OPT_GHOST { master_notify($1); YYABORT; }
+@@ -543,6 +546,7 @@ daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; }
+ | OPT_GHOST { ghost = 1; }
+ | OPT_VERBOSE { verbose = 1; }
+ | OPT_DEBUG { debug = 1; }
++ | OPT_RANDOM { random_selection = 1; }
+ ;
+
+ mount_option: OPTION
+@@ -600,6 +604,7 @@ static void local_init_vars(void)
+ debug = 0;
+ timeout = -1;
+ ghost = defaults_get_browse_mode();
++ random_selection = global_random_selection;
+ tmp_argv = NULL;
+ tmp_argc = 0;
+ local_argv = NULL;
+@@ -790,6 +795,7 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne
+ }
+ set_mnt_logging(ap);
+ }
++ entry->ap->random_selection = random_selection;
+
+ /*
+ source = master_find_map_source(entry, type, format,
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index ff69a24..013a15a 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -324,6 +324,7 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ -g|--ghost|-?browse { return(OPT_GHOST); }
+ -v|--verbose { return(OPT_VERBOSE); }
+ -d|--debug { return(OPT_DEBUG); }
++ -r|--random-multimount-selection { return(OPT_RANDOM); }
+
+ {OPTWS}","{OPTWS} { return(COMMA); }
+
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index 249c9a7..ab5ab1e 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -146,6 +146,12 @@ to prevent symlinking of local NFS mounts. Nowadays it can be used to
+ prevent bind mounting of local NFS filesystems as well. If you need to
+ prevent bind mounting for only specific entrys in a map then this
+ can be done by adding the "port=" mount option to the given entries.
++.TP
++.I "\-r, \-\-random-multimount-selection"
++Enables the use of ramdom selection when choosing a host from a
++list of replicated servers. This option is applied to this mount
++only, overriding the global setting that may be specified on the
++command line.
+ .SH GENERAL SYSTEM DEFAULTS CONFIGURATION
+ .P
+ The default value of several general settings may be changed in the
+diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
+index e7a9a8a..e4480c5 100644
+--- a/modules/mount_nfs.c
++++ b/modules/mount_nfs.c
+@@ -137,7 +137,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ warn(ap->logopt, MODPREFIX "no hosts available");
+ return 1;
+ }
+- prune_host_list(&hosts, vers, nfsoptions);
++ prune_host_list(&hosts, vers, nfsoptions, ap->random_selection);
+
+ if (!hosts) {
+ warn(ap->logopt, MODPREFIX "no hosts available");
+diff --git a/modules/replicated.c b/modules/replicated.c
+index 0764d4a..e15587c 100644
+--- a/modules/replicated.c
++++ b/modules/replicated.c
+@@ -74,8 +74,6 @@
+ #define max(x, y) (x >= y ? x : y)
+ #define mmax(x, y, z) (max(x, y) == x ? max(x, z) : max(y, z))
+
+-extern unsigned int random_selection;
+-
+ void seed_random(void)
+ {
+ int fd;
+@@ -392,7 +390,7 @@ static unsigned short get_port_option(const char *options)
+ static unsigned int get_nfs_info(struct host *host,
+ struct conn_info *pm_info, struct conn_info *rpc_info,
+ const char *proto, unsigned int version,
+- const char *options)
++ const char *options, unsigned int random_selection)
+ {
+ char *have_port_opt = options ? strstr(options, "port=") : NULL;
+ struct pmap parms;
+@@ -535,7 +533,9 @@ done_ver:
+ return supported;
+ }
+
+-static int get_vers_and_cost(struct host *host, unsigned int version, const char *options)
++static int get_vers_and_cost(struct host *host,
++ unsigned int version, const char *options,
++ unsigned int random_selection)
+ {
+ struct conn_info pm_info, rpc_info;
+ time_t timeout = RPC_TIMEOUT;
+@@ -559,7 +559,9 @@ static int get_vers_and_cost(struct host *host, unsigned int version, const char
+ vers &= version;
+
+ if (version & UDP_REQUESTED) {
+- supported = get_nfs_info(host, &pm_info, &rpc_info, "udp", vers, options);
++ supported = get_nfs_info(host,
++ &pm_info, &rpc_info, "udp", vers,
++ options, random_selection);
+ if (supported) {
+ ret = 1;
+ host->version |= (supported << 8);
+@@ -567,7 +569,9 @@ static int get_vers_and_cost(struct host *host, unsigned int version, const char
+ }
+
+ if (version & TCP_REQUESTED) {
+- supported = get_nfs_info(host, &pm_info, &rpc_info, "tcp", vers, options);
++ supported = get_nfs_info(host,
++ &pm_info, &rpc_info, "tcp", vers,
++ options, random_selection);
+ if (supported) {
+ ret = 1;
+ host->version |= supported;
+@@ -577,7 +581,9 @@ static int get_vers_and_cost(struct host *host, unsigned int version, const char
+ return ret;
+ }
+
+-static int get_supported_ver_and_cost(struct host *host, unsigned int version, const char *options)
++static int get_supported_ver_and_cost(struct host *host,
++ unsigned int version, const char *options,
++ unsigned int random_selection)
+ {
+ char *have_port_opt = options ? strstr(options, "port=") : NULL;
+ struct conn_info pm_info, rpc_info;
+@@ -695,7 +701,9 @@ done:
+ return 0;
+ }
+
+-int prune_host_list(struct host **list, unsigned int vers, const char *options)
++int prune_host_list(struct host **list,
++ unsigned int vers, const char *options,
++ unsigned int random_selection)
+ {
+ struct host *this, *last, *first;
+ struct host *new = NULL;
+@@ -734,7 +742,8 @@ int prune_host_list(struct host **list, unsigned int vers, const char *options)
+ break;
+
+ if (this->name) {
+- status = get_vers_and_cost(this, vers, options);
++ status = get_vers_and_cost(this, vers,
++ options, random_selection);
+ if (!status) {
+ if (this == first) {
+ first = next;
+@@ -824,7 +833,9 @@ int prune_host_list(struct host **list, unsigned int vers, const char *options)
+ remove_host(list, this);
+ add_host(&new, this);
+ } else {
+- status = get_supported_ver_and_cost(this, selected_version, options);
++ status = get_supported_ver_and_cost(this,
++ selected_version, options,
++ random_selection);
+ if (status) {
+ this->version = selected_version;
+ remove_host(list, this);
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index fe7ae00..ca171a4 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -34,6 +34,7 @@
+ - fix lack of ferror() checking when reading files.
+ - fix typo in autofs(5) man page.
+ - fix map entry expansion when undefined macro is present.
++- remove unused export validation code.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
+index 831d456..d79a94f 100644
+--- a/lib/rpc_subs.c
++++ b/lib/rpc_subs.c
+@@ -52,10 +52,7 @@
+ /* Get numeric value of the n bits starting at position p */
+ #define getbits(x, p, n) ((x >> (p + 1 - n)) & ~(~0 << n))
+
+-static char *domain = NULL;
+-
+ inline void dump_core(void);
+-static pthread_mutex_t networks_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+ /*
+ * Create a UDP RPC client
+@@ -764,573 +761,6 @@ void rpc_exports_free(exports list)
+ return;
+ }
+
+-static int masked_match(const char *addr, const char *mask)
+-{
+- char buf[MAX_IFC_BUF], *ptr;
+- struct sockaddr_in saddr;
+- struct sockaddr_in6 saddr6;
+- struct ifconf ifc;
+- struct ifreq *ifr;
+- int sock, cl_flags, ret, i, is_ipv4, is_ipv6;
+- unsigned int msize;
+-
+- sock = socket(AF_INET, SOCK_DGRAM, 0);
+- if (sock < 0) {
+- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "socket creation failed: %s", estr);
+- return 0;
+- }
+-
+- if ((cl_flags = fcntl(sock, F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(sock, F_SETFD, cl_flags);
+- }
+-
+- ifc.ifc_len = sizeof(buf);
+- ifc.ifc_req = (struct ifreq *) buf;
+- ret = ioctl(sock, SIOCGIFCONF, &ifc);
+- if (ret == -1) {
+- close(sock);
+- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "ioctl: %s", estr);
+- return 0;
+- }
+-
+- is_ipv4 = is_ipv6 = 0;
+- is_ipv4 = inet_pton(AF_INET, addr, &saddr.sin_addr);
+- if (!is_ipv4)
+- is_ipv6 = inet_pton(AF_INET6, addr, &saddr6.sin6_addr);
+-
+- if (strchr(mask, '.')) {
+- struct sockaddr_in maddr;
+- uint32_t ma;
+- int i = 0;
+-
+- ret = inet_aton(mask, &maddr.sin_addr);
+- if (!ret) {
+- close(sock);
+- return 0;
+- }
+-
+- ma = ntohl((uint32_t) maddr.sin_addr.s_addr);
+- while (!(ma & 1)) {
+- i++;
+- ma = ma >> 1;
+- }
+-
+- msize = i;
+- } else
+- msize = atoi(mask);
+-
+- i = 0;
+- ptr = (char *) &ifc.ifc_buf[0];
+-
+- while (ptr < buf + ifc.ifc_len) {
+- ifr = (struct ifreq *) ptr;
+-
+- switch (ifr->ifr_addr.sa_family) {
+- case AF_INET:
+- {
+- struct sockaddr_in *if_addr;
+- uint32_t m, ia, ha;
+-
+- if (!is_ipv4 || msize > 32)
+- break;
+-
+- m = -1;
+- m = m << (32 - msize);
+- ha = ntohl((uint32_t) saddr.sin_addr.s_addr);
+-
+- if_addr = (struct sockaddr_in *) &ifr->ifr_addr;
+- ia = ntohl((uint32_t) if_addr->sin_addr.s_addr);
+-
+- if ((ia & m) == (ha & m)) {
+- close(sock);
+- return 1;
+- }
+- break;
+- }
+-
+- /* glibc rpc only understands IPv4 atm */
+- case AF_INET6:
+- break;
+-
+- default:
+- break;
+- }
+-
+- i++;
+- ptr = (char *) &ifc.ifc_req[i];
+- }
+-
+- close(sock);
+- return 0;
+-}
+-
+-/*
+- * This function has been adapted from the match_patern function
+- * found in OpenSSH and is used in accordance with the copyright
+- * notice found their.
+- *
+- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland.
+- */
+-/*
+- * Returns true if the given string matches the pattern (which
+- * may contain ? and * as wildcards), and zero if it does not
+- * match.
+- */
+-static int pattern_match(const char *s, const char *pattern)
+-{
+- for (;;) {
+- /* If at end of pattern, accept if also at end of string. */
+- if (!*pattern)
+- return !*s;
+-
+- if (*pattern == '*') {
+- /* Skip the asterisk. */
+- pattern++;
+-
+- /* If at end of pattern, accept immediately. */
+- if (!*pattern)
+- return 1;
+-
+- /* If next character in pattern is known, optimize. */
+- if (*pattern != '?' && *pattern != '*') {
+- /*
+- * Look instances of the next character in
+- * pattern, and try to match starting from
+- * those.
+- */
+- for (; *s; s++)
+- if (*s == *pattern &&
+- pattern_match(s + 1, pattern + 1))
+- return 1;
+-
+- /* Failed. */
+- return 0;
+- }
+- /*
+- * Move ahead one character at a time and try to
+- * match at each position.
+- */
+- for (; *s; s++)
+- if (pattern_match(s, pattern))
+- return 1;
+- /* Failed. */
+- return 0;
+- }
+- /*
+- * There must be at least one more character in the string.
+- * If we are at the end, fail.
+- */
+- if (!*s)
+- return 0;
+-
+- /* Check if the next character of the string is acceptable. */
+- if (*pattern != '?' && *pattern != *s)
+- return 0;
+-
+- /* Move to the next character, both in string and in pattern. */
+- s++;
+- pattern++;
+- }
+- /* NOTREACHED */
+-}
+-
+-static int name_match(const char *name, const char *pattern)
+-{
+- int ret;
+-
+- if (strchr(pattern, '*') || strchr(pattern, '?'))
+- ret = pattern_match(name, pattern);
+- else {
+- ret = !memcmp(name, pattern, strlen(pattern));
+- /* Name could still be a netgroup (Solaris) */
+- if (!ret)
+- ret = innetgr(pattern, name, NULL, domain);
+- }
+-
+- return ret;
+-}
+-
+-static int fqdn_match(const char *pattern)
+-{
+- char buf[MAX_IFC_BUF], *ptr;
+- struct ifconf ifc;
+- struct ifreq *ifr;
+- int sock, cl_flags, ret, i;
+- char fqdn[NI_MAXHOST + 1];
+-
+- sock = socket(AF_INET, SOCK_DGRAM, 0);
+- if (sock < 0) {
+- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "socket creation failed: %s", estr);
+- return 0;
+- }
+-
+- if ((cl_flags = fcntl(sock, F_GETFD, 0)) != -1) {
+- cl_flags |= FD_CLOEXEC;
+- fcntl(sock, F_SETFD, cl_flags);
+- }
+-
+- ifc.ifc_len = sizeof(buf);
+- ifc.ifc_req = (struct ifreq *) buf;
+- ret = ioctl(sock, SIOCGIFCONF, &ifc);
+- if (ret == -1) {
+- close(sock);
+- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(LOGOPT_ANY, "ioctl: %s", estr);
+- return 0;
+- }
+-
+- i = 0;
+- ptr = (char *) &ifc.ifc_buf[0];
+-
+- while (ptr < buf + ifc.ifc_len) {
+- ifr = (struct ifreq *) ptr;
+-
+- switch (ifr->ifr_addr.sa_family) {
+- case AF_INET:
+- {
+- socklen_t slen = sizeof(struct sockaddr);
+-
+- ret = getnameinfo(&ifr->ifr_addr, slen, fqdn,
+- NI_MAXHOST, NULL, 0, NI_NAMEREQD);
+- if (!ret) {
+- ret = name_match(fqdn, pattern);
+- if (ret) {
+- close(sock);
+- return 1;
+- }
+- }
+- break;
+- }
+-
+- /* glibc rpc only understands IPv4 atm */
+- case AF_INET6:
+- break;
+-
+- default:
+- break;
+- }
+-
+- i++;
+- ptr = (char *) &ifc.ifc_req[i];
+- }
+-
+- close(sock);
+- return 0;
+-}
+-
+-static int string_match(const char *myname, const char *pattern)
+-{
+- struct addrinfo hints, *ni;
+- int ret;
+-
+- /* Try simple name match first */
+- ret = name_match(myname, pattern);
+- if (ret)
+- goto done;
+-
+- memset(&hints, 0, sizeof(hints));
+- hints.ai_flags = AI_CANONNAME;
+- hints.ai_family = 0;
+- hints.ai_socktype = 0;
+-
+- /* See if our canonical name matches */
+- if (getaddrinfo(myname, NULL, &hints, &ni) == 0) {
+- ret = name_match(ni->ai_canonname, pattern);
+- freeaddrinfo(ni);
+- } else
+- warn(LOGOPT_ANY, "name lookup failed: %s", gai_strerror(ret));
+- if (ret)
+- goto done;
+-
+- /* Lastly see if the name of an interfaces matches */
+- ret = fqdn_match(pattern);
+-done:
+- return ret;
+-}
+-
+-static unsigned int inet_get_net_len(uint32_t net)
+-{
+- int i;
+-
+- for (i = 0; i < 32; i += 8) {
+- if (getbits(net, i + 7, 8))
+- break;
+- }
+-
+- return (unsigned int) 32 - i;
+-}
+-
+-static char *inet_fill_net(const char *net_num, char *net)
+-{
+- char *np;
+- unsigned int dots = 3;
+-
+- if (strlen(net_num) > INET_ADDRSTRLEN)
+- return NULL;
+-
+- if (!isdigit(*net_num))
+- return NULL;
+-
+- *net = '\0';
+- strcpy(net, net_num);
+-
+- np = net;
+- while (*np++) {
+- if (*np == '.') {
+- np++;
+- dots--;
+- if (!*np && dots)
+- strcat(net, "0");
+- continue;
+- }
+-
+- if ((*np && !isdigit(*np)) || dots < 0) {
+- *net = '\0';
+- return NULL;
+- }
+- }
+-
+- while (dots--)
+- strcat(net, ".0");
+-
+- return net;
+-}
+-
+-static int match_network(const char *network)
+-{
+- struct netent *pnent, nent;
+- const char *pcnet;
+- char *net, cnet[MAX_NETWORK_LEN], mask[4], *pmask;
+- unsigned int size;
+- size_t l_network = strlen(network) + 1;
+- int status;
+-
+- if (l_network > MAX_NETWORK_LEN) {
+- error(LOGOPT_ANY,
+- "match string \"%s\" too long", network);
+- return 0;
+- }
+-
+- net = alloca(l_network);
+- if (!net)
+- return 0;
+- memset(net, 0, l_network);
+- strcpy(net, network);
+-
+- if ((pmask = strchr(net, '/')))
+- *pmask++ = '\0';
+-
+- status = pthread_mutex_lock(&networks_mutex);
+- if (status)
+- fatal(status);
+-
+- pnent = getnetbyname(net);
+- if (pnent)
+- memcpy(&nent, pnent, sizeof(struct netent));
+-
+- status = pthread_mutex_unlock(&networks_mutex);
+- if (status)
+- fatal(status);
+-
+- if (pnent) {
+- uint32_t n_net;
+-
+- switch (nent.n_addrtype) {
+- case AF_INET:
+- n_net = ntohl(nent.n_net);
+- pcnet = inet_ntop(AF_INET, &n_net, cnet, INET_ADDRSTRLEN);
+- if (!pcnet)
+- return 0;
+-
+- if (!pmask) {
+- size = inet_get_net_len(nent.n_net);
+- if (!size)
+- return 0;
+- }
+- break;
+-
+- case AF_INET6:
+- return 0;
+-
+- default:
+- return 0;
+- }
+- } else {
+- int ret;
+-
+- if (strchr(net, ':')) {
+- return 0;
+- } else {
+- struct in_addr addr;
+-
+- pcnet = inet_fill_net(net, cnet);
+- if (!pcnet)
+- return 0;
+-
+- ret = inet_pton(AF_INET, pcnet, &addr);
+- if (ret <= 0)
+- return 0;
+-
+- if (!pmask) {
+- uint32_t nl_addr = htonl(addr.s_addr);
+- size = inet_get_net_len(nl_addr);
+- if (!size)
+- return 0;
+- }
+- }
+- }
+-
+- if (!pmask) {
+- if (sprintf(mask, "%u", size) <= 0)
+- return 0;
+- pmask = mask;
+- }
+-
+- debug(LOGOPT_ANY, "pcnet %s pmask %s", pcnet, pmask);
+-
+- return masked_match(pcnet, pmask);
+-}
+-
+-/*
+- * Two export formats need to be understood to cater for different
+- * NFS server exports.
+- *
+- * (host|wildcard|network[/mask]|@netgroup)
+- *
+- * A host name which can be cannonical.
+- * A wildcard host name containing "*" and "?" with the usual meaning.
+- * A network in numbers and dots form with optional mask given as
+- * either a length or as numbers and dots.
+- * A netgroup identified by the prefix "@".
+- *
+- * [-](host|domain suffix|netgroup|@network[/mask])
+- *
+- * A host name which can be cannonical.
+- * A domain suffix identified by a leading "." which will match all
+- * hosts in the given domain.
+- * A netgroup.
+- * A network identified by the prefix "@" given in numbers and dots
+- * form or as a network name with optional mask given as either a
+- * length or as numbers and dots.
+- * A "-" prefix can be appended to indicate access is denied.
+- */
+-static int host_match(char *pattern)
+-{
+- unsigned int negate = (*pattern == '-');
+- const char *m_pattern = (negate ? pattern + 1 : pattern);
+- char myname[MAXHOSTNAMELEN + 1] = "\0";
+- int ret = 0;
+-
+- if (gethostname(myname, MAXHOSTNAMELEN))
+- return 0;
+-
+- if (yp_get_default_domain(&domain))
+- domain = NULL;
+-
+- if (*m_pattern == '@') {
+- /*
+- * The pattern begins with an "@" so it's a network
+- * spec or it's a netgroup.
+- */
+- ret = match_network(m_pattern + 1);
+- if (!ret)
+- ret = innetgr(m_pattern + 1, myname, NULL, domain);
+- } else if (*m_pattern == '.') {
+- size_t m_len = strlen(m_pattern);
+- char *has_dot = strchr(myname, '.');
+- /*
+- * The pattern starts with a "." so it's a domain spec
+- * of some sort.
+- *
+- * If the host name contains a dot then it must be either
+- * a cannonical name or a simple NIS name.domain. So
+- * perform a string match. Otherwise, append the domain
+- * pattern to our simple name and try a wildcard pattern
+- * match against the interfaces.
+- */
+- if (has_dot) {
+- if (strlen(has_dot) == m_len)
+- ret = !memcmp(has_dot, m_pattern, m_len);
+- } else {
+- char *w_pattern = alloca(m_len + 2);
+- if (w_pattern) {
+- strcpy(w_pattern, "*");
+- strcat(w_pattern, m_pattern);
+- ret = fqdn_match(w_pattern);
+- }
+- }
+- } else if (!strcmp(m_pattern, "gss/krb5")) {
+- /* Leave this to the GSS layer */
+- return 1;
+- } else {
+- /*
+- * Otherwise it's a network name or host name
+- */
+- ret = match_network(m_pattern);
+- if (!ret)
+- /* if not then try to match host name */
+- ret = string_match(myname, m_pattern);
+- }
+-
+- if (negate && ret)
+- ret = -1;
+-
+- return ret;
+-}
+-
+-static int rpc_export_allowed(groups grouplist)
+-{
+- groups grp = grouplist;
+-
+- /* NULL group list => everyone */
+- if (!grp)
+- return 1;
+-
+- while (grp) {
+- int allowed = host_match(grp->gr_name);
+- /* Explicitly denied access */
+- if (allowed == -1)
+- return 0;
+- else if (allowed)
+- return 1;
+- grp = grp->gr_next;
+- }
+- return 0;
+-}
+-
+-exports rpc_exports_prune(exports list)
+-{
+- exports head = list;
+- exports exp;
+- exports last;
+- int res;
+-
+- exp = list;
+- last = NULL;
+- while (exp) {
+- res = rpc_export_allowed(exp->ex_groups);
+- if (!res) {
+- if (last == NULL) {
+- head = exp->ex_next;
+- rpc_export_free(exp);
+- exp = head;
+- } else {
+- last->ex_next = exp->ex_next;
+- rpc_export_free(exp);
+- exp = last->ex_next;
+- }
+- continue;
+- }
+- last = exp;
+- exp = exp->ex_next;
+- }
+- return head;
+-}
+-
+ exports rpc_get_exports(const char *host, long seconds, long micros, unsigned int option)
+ {
+ struct conn_info info;
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index 1f8fa15..d711611 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -45,7 +45,6 @@ struct lookup_context {
+ int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+
+ exports rpc_get_exports(const char *host, long seconds, long micros, unsigned int option);
+-exports rpc_exports_prune(exports list);
+ void rpc_exports_free(exports list);
+
+ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **context)
+@@ -207,9 +206,6 @@ done:
+
+ exp = rpc_get_exports(name, 10, 0, RPC_CLOSE_NOLINGER);
+
+- /* Check exports for obvious ones we don't have access to */
+- /*exp = rpc_exports_prune(exp);*/
+-
+ mapent = NULL;
+ while (exp) {
+ if (mapent) {
--- /dev/null
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index 1007de4..23ea07d 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -1088,8 +1088,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ if (status == NSS_STATUS_COMPLETED)
+ return NSS_STATUS_SUCCESS;
+
+- debug(ap->logopt,
+- MODPREFIX "check indirect map lookup failed");
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map",
++ name);
+
+ return NSS_STATUS_NOTFOUND;
+ }
+@@ -1130,7 +1131,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ }
+ cache_unlock(mc);
+ }
+- }
++ } else
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map.", name);
+
+ if (ret)
+ return NSS_STATUS_TRYAGAIN;
+diff --git a/modules/lookup_hesiod.c b/modules/lookup_hesiod.c
+index 649e24c..737a47e 100644
+--- a/modules/lookup_hesiod.c
++++ b/modules/lookup_hesiod.c
+@@ -129,8 +129,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ if (!hes_result || !hes_result[0]) {
+ /* Note: it is not clear to me how to distinguish between
+ * the "no search results" case and other failures. --JM */
+- warn(ap->logopt,
+- MODPREFIX "entry \"%s\" not found in map", name);
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map", name);
+ status = pthread_mutex_unlock(&hesiod_mutex);
+ if (status)
+ fatal(status);
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 4dea3b2..bad48bb 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -2089,8 +2089,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
+ free(lkp_key);
+ if (status) {
+- debug(ap->logopt,
+- MODPREFIX "check indirect map failure");
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map",
++ name);
+ return status;
+ }
+ }
+@@ -2129,7 +2130,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ }
+ cache_unlock(mc);
+ }
+- }
++ } else
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map", name);
+
+ if (ret)
+ return NSS_STATUS_TRYAGAIN;
+diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
+index e948c14..bb1ca42 100644
+--- a/modules/lookup_nisplus.c
++++ b/modules/lookup_nisplus.c
+@@ -512,8 +512,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
+ if (status) {
+- debug(ap->logopt,
+- MODPREFIX "check indirect map failure");
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map",
++ name);
+ return status;
+ }
+ }
+@@ -551,7 +552,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ }
+ cache_unlock(mc);
+ }
+- }
++ } else
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map", name);
+
+ if (ret)
+ return NSS_STATUS_NOTFOUND;
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index 6c20145..e8ca8e8 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -604,8 +604,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
+ free(lkp_key);
+ if (status) {
+- debug(ap->logopt,
+- MODPREFIX "check indirect map lookup failed");
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map",
++ name);
+ return status;
+ }
+ }
+@@ -643,7 +644,9 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ }
+ cache_unlock(mc);
+ }
+- }
++ } else
++ error(ap->logopt,
++ MODPREFIX "key \"%s\" not found in map", name);
+
+ if (ret)
+ return NSS_STATUS_TRYAGAIN;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index a2a782d..9a2a8c1 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -26,6 +26,7 @@
+ - fix LDAP schema discovery.
+ - add SEARCH_BASE configuration option.
+ - work around segv at exit due to libxml2 tsd usage.
++- re-read config on HUP signal.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index e9cae4e..3d6a703 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -986,6 +986,8 @@ static void *do_read_master(void *arg)
+ if (status)
+ fatal(status);
+
++ defaults_read_config();
++
+ status = master_read_master(master, age, readall);
+
+ master->reading = 0;
+diff --git a/lib/master.c b/lib/master.c
+index da05bb6..637ce04 100644
+--- a/lib/master.c
++++ b/lib/master.c
+@@ -1169,6 +1169,10 @@ int master_mount_mounts(struct master *master, time_t age, int readall)
+ continue;
+ }
+
++ master_source_writelock(this);
++ lookup_close_lookup(ap);
++ master_source_unlock(this);
++
+ cache_readlock(nc);
+ ne = cache_lookup_distinct(nc, this->path);
+ if (ne && this->age > ne->age) {
+diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c
+index 8821f84..9aac792 100644
+--- a/modules/cyrus-sasl.c
++++ b/modules/cyrus-sasl.c
+@@ -528,6 +528,7 @@ sasl_do_kinit(struct lookup_context *ctxt)
+ return 0;
+
+ out_cleanup_unparse:
++ krb5cc_in_use--;
+ krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
+ out_cleanup_cc:
+ status = pthread_mutex_lock(&krb5cc_mutex);
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 49a9a9b..2baf8b8 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -174,7 +174,7 @@ LDAP *init_ldap_connection(struct lookup_context *ctxt)
+ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
+ {
+ char buf[PARSE_MAX_BUF];
+- char *query, *dn;
++ char *query, *dn, *qdn;
+ LDAPMessage *result = NULL, *e;
+ struct ldap_searchdn *sdns = NULL;
+ char *attrs[2];
+@@ -225,15 +225,18 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+
+ if (!ctxt->base) {
+ sdns = defaults_get_searchdns();
+- if (sdns)
++ if (sdns) {
++ if (ctxt->sdns)
++ defaults_free_searchdns(ctxt->sdns);
+ ctxt->sdns = sdns;
++ }
+ }
+
+- if (!sdns)
++ if (!ctxt->sdns)
+ rv = ldap_search_s(ldap, ctxt->base,
+ scope, query, attrs, 0, &result);
+ else {
+- struct ldap_searchdn *this = sdns;
++ struct ldap_searchdn *this = ctxt->sdns;
+
+ debug(LOGOPT_NONE, MODPREFIX
+ "check search base list");
+@@ -269,7 +272,6 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ if (e) {
+ dn = ldap_get_dn(ldap, e);
+ debug(LOGOPT_NONE, MODPREFIX "query dn %s", dn);
+- ldap_msgfree(result);
+ } else {
+ debug(LOGOPT_NONE,
+ MODPREFIX "query succeeded, no matches for %s",
+@@ -278,7 +280,16 @@ static int get_query_dn(LDAP *ldap, struct lookup_context *ctxt, const char *cla
+ return 0;
+ }
+
+- ctxt->qdn = dn;
++ qdn = strdup(dn);
++ ldap_memfree(dn);
++ ldap_msgfree(result);
++ if (!qdn)
++ return 0;
++
++ if (ctxt->qdn)
++ free(ctxt->qdn);
++
++ ctxt->qdn = qdn;
+
+ return 1;
+ }
+@@ -1018,7 +1029,7 @@ static void free_context(struct lookup_context *ctxt)
+ if (ctxt->mapname)
+ free(ctxt->mapname);
+ if (ctxt->qdn)
+- ldap_memfree(ctxt->qdn);
++ free(ctxt->qdn);
+ if (ctxt->server)
+ free(ctxt->server);
+ if (ctxt->cur_host)
+@@ -1600,14 +1611,14 @@ static int lookup_one(struct autofs_point *ap,
+ }
+ query[ql] = '\0';
+
+- debug(ap->logopt,
+- MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn);
+-
+ /* Initialize the LDAP context. */
+ ldap = do_connect(ctxt);
+ if (!ldap)
+ return CHE_FAIL;
+
++ debug(ap->logopt,
++ MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn);
++
+ rv = ldap_search_s(ldap, ctxt->qdn, scope, query, attrs, 0, &result);
+
+ if ((rv != LDAP_SUCCESS) || !result) {
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index be50aad..3557b16 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -45,6 +45,7 @@
+ - update negative mount timeout handling.
+ - fix large group handling (Ryan Thomas).
+ - fix for dynamic logging breaking non-sasl build (Guillaume Rousse)
++- eliminate NULL proc ping for singleton host or local mounts.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/replicated.c b/modules/replicated.c
+index 14b20a9..90b2925 100644
+--- a/modules/replicated.c
++++ b/modules/replicated.c
+@@ -725,19 +725,21 @@ int prune_host_list(unsigned logopt, struct host **list,
+ while (this && this->proximity == PROXIMITY_LOCAL)
+ this = this->next;
+
+- proximity = PROXIMITY_LOCAL;
+- if (this)
+- proximity = this->proximity;
++ /*
++ * Check for either a list containing only proximity local hosts
++ * or a single host entry whose proximity isn't local. If so
++ * return immediately as we don't want to add probe latency for
++ * the common case of a single filesystem mount request.
++ */
++ if (!this || !this->next)
++ return 1;
+
++ proximity = this->proximity;
++ first = this;
+ this = first;
+ while (this) {
+ struct host *next = this->next;
+
+- if (this->proximity == PROXIMITY_LOCAL) {
+- this = next;
+- continue;
+- }
+-
+ if (this->proximity != proximity)
+ break;
+
+@@ -758,10 +760,6 @@ int prune_host_list(unsigned logopt, struct host **list,
+
+ last = this;
+
+- /* If there are only local entries on the list, just return it. */
+- if (!first)
+- return 0;
+-
+ /* Select NFS version of highest number of closest servers */
+
+ v4_tcp_count = v3_tcp_count = v2_tcp_count = 0;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 3557b16..7e58092 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -46,6 +46,7 @@
+ - fix large group handling (Ryan Thomas).
+ - fix for dynamic logging breaking non-sasl build (Guillaume Rousse)
+ - eliminate NULL proc ping for singleton host or local mounts.
++- fix incorrect read/write size of startup status token (Matthias Koenig).
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 7becad5..f31ec11 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -1125,7 +1125,7 @@ static void become_daemon(unsigned foreground)
+ if (pid > 0) {
+ int r;
+ close(start_pipefd[1]);
+- r = read(start_pipefd[0], pst_stat, sizeof(pst_stat));
++ r = read(start_pipefd[0], pst_stat, sizeof(*pst_stat));
+ if (r < 0)
+ exit(1);
+ exit(*pst_stat);
+@@ -2061,12 +2061,12 @@ int main(int argc, char *argv[])
+ if (!master_read_master(master_list, age, 0)) {
+ master_kill(master_list);
+ *pst_stat = 3;
+- res = write(start_pipefd[1], pst_stat, sizeof(pst_stat));
++ res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
+ close(start_pipefd[1]);
+ exit(3);
+ }
+
+- res = write(start_pipefd[1], pst_stat, sizeof(pst_stat));
++ res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
+ close(start_pipefd[1]);
+
+ state_mach_thid = pthread_self();
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index ddfa6f1..2db9b39 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -30,6 +30,7 @@
+ - add LDAP_URI, LDAP_TIMEOUT and LDAP_NETWORK_TIMEOUT configuration options.
+ - fix forground logging and add option to man page.
+ - remove unjustified, nasty comment about krb5 package.
++- fix deadlock in submount mount module.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
+index f8d8ed2..c45b91b 100644
+--- a/modules/mount_autofs.c
++++ b/modules/mount_autofs.c
+@@ -215,6 +215,8 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ return 1;
+ }
+
++ mounts_mutex_lock(ap);
++
+ status = pthread_mutex_lock(&suc.mutex);
+ if (status) {
+ crit(ap->logopt,
+@@ -227,8 +229,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ suc.done = 0;
+ suc.status = 0;
+
+- mounts_mutex_lock(ap);
+-
+ if (pthread_create(&thid, NULL, handle_mounts, nap)) {
+ crit(ap->logopt,
+ MODPREFIX
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index fdd07d1..fe7ae00 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -33,6 +33,7 @@
+ - fix deadlock in submount mount module.
+ - fix lack of ferror() checking when reading files.
+ - fix typo in autofs(5) man page.
++- fix map entry expansion when undefined macro is present.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 5e14c75..079bda6 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -186,8 +186,7 @@ int expandsunent(const char *src, char *dst, const char *key,
+ dst += l;
+ }
+ len += l;
+- } else
+- return 0;
++ }
+ src = p + 1;
+ } else {
+ p = src;
+@@ -201,8 +200,7 @@ int expandsunent(const char *src, char *dst, const char *key,
+ dst += l;
+ }
+ len += l;
+- } else
+- return 0;
++ }
+ src = p;
+ }
+ break;
--- /dev/null
+diff --git a/CHANGELOG b/CHANGELOG
+index 0e9dc51..054d4df 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -21,6 +21,7 @@
+ - if there's no "automount" entry in nsswitch.conf use "files" source.
+ - add LDAP schema discovery if no schema is configured.
+ - add random selection as a master map entry option.
++- fix couple of edge case parse fails of timeout option.
+
+ 18/06/2007 autofs-5.0.2
+ -----------------------
+diff --git a/lib/master_tok.l b/lib/master_tok.l
+index 013a15a..2735223 100644
+--- a/lib/master_tok.l
++++ b/lib/master_tok.l
+@@ -313,7 +313,7 @@ OPTTOUT (-t{OPTWS}|-t{OPTWS}={OPTWS}|--timeout{OPTWS}|--timeout{OPTWS}={OPTWS})
+ return(DDASH);
+ }
+
+- {OPTTOUT} { return(OPT_TIMEOUT); }
++ {OPTTOUT}/{NUMBER} { return(OPT_TIMEOUT); }
+
+ {NUMBER} {
+ master_lval.longtype = atol(master_text);