]> git.pld-linux.org Git - packages/autofs.git/commitdiff
- "few" official patches
authorPaweł Gołaszewski <blues@pld-linux.org>
Mon, 24 Dec 2007 11:25:02 +0000 (11:25 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    autofs-5.0.2-add-ferror-check.patch -> 1.1
    autofs-5.0.2-add-krb5-include.patch -> 1.1
    autofs-5.0.2-add-ldap-schema-discovery-fix-2.patch -> 1.1
    autofs-5.0.2-add-ldap-schema-discovery-fix.patch -> 1.1
    autofs-5.0.2-add-ldap-schema-discovery.patch -> 1.1
    autofs-5.0.2-add-missing-multi-support.patch -> 1.1
    autofs-5.0.2-add-multi-nsswitch-lookup.patch -> 1.1
    autofs-5.0.2-add-multiple-server-selection-option-fix.patch -> 1.1
    autofs-5.0.2-add-multiple-server-selection-option.patch -> 1.1
    autofs-5.0.2-autofs-5-typo.patch -> 1.1
    autofs-5.0.2-bad-proto-init.patch -> 1.1
    autofs-5.0.2-basedn-with-spaces-fix-2.patch -> 1.1
    autofs-5.0.2-basedn-with-spaces-fix.patch -> 1.1
    autofs-5.0.2-basedn-with-spaces.patch -> 1.1
    autofs-5.0.2-check-auto_master.patch -> 1.1
    autofs-5.0.2-check-mtab-updated-fix.patch -> 1.1
    autofs-5.0.2-check-mtab-updated.patch -> 1.1
    autofs-5.0.2-cleanup-krb5-comment.patch -> 1.1
    autofs-5.0.2-consistent-random-selection-option-name.patch -> 1.1
    autofs-5.0.2-default-nsswitch.patch -> 1.1
    autofs-5.0.2-dont-fail-on-empty-master-fix.patch -> 1.1
    autofs-5.0.2-dont-fail-on-empty-master.patch -> 1.1
    autofs-5.0.2-dynamic-logging-fixes.patch -> 1.1
    autofs-5.0.2-dynamic-logging-non-sasl.patch -> 1.1
    autofs-5.0.2-dynamic-logging.patch -> 1.1
    autofs-5.0.2-external-cred-cache.patch -> 1.1
    autofs-5.0.2-fix-dnattr-parse.patch -> 1.1
    autofs-5.0.2-fix-largefile-dumbness.patch -> 1.1
    autofs-5.0.2-fix-mount-nfs-nosymlink.patch -> 1.1
    autofs-5.0.2-fix-nfs-version-in-get-supported-ver-and-cost.patch -> 1.1
    autofs-5.0.2-fix-off-by-one-lookup.patch -> 1.1
    autofs-5.0.2-fix-offset-dir-create.patch -> 1.1
    autofs-5.0.2-fix-recursive-loopback-mounts.patch -> 1.1
    autofs-5.0.2-foreground-logging.patch -> 1.1
    autofs-5.0.2-hi-res-time.patch -> 1.1
    autofs-5.0.2-hosts-nosuid-default.patch -> 1.1
    autofs-5.0.2-improve-server-unavail-fix.patch -> 1.1
    autofs-5.0.2-improve-server-unavail.patch -> 1.1
    autofs-5.0.2-instance-stale-mark.patch -> 1.1
    autofs-5.0.2-large-groups.patch -> 1.1
    autofs-5.0.2-ldap-check-star.patch -> 1.1
    autofs-5.0.2-ldap-percent-hack.patch -> 1.1
    autofs-5.0.2-ldap-schema-discovery-config-update.patch -> 1.1
    autofs-5.0.2-ldap-search-basedn-list.patch -> 1.1
    autofs-5.0.2-libxml2-workaround.patch -> 1.1
    autofs-5.0.2-log-map-reload.patch -> 1.1
    autofs-5.0.2-negative-timeout-update.patch -> 1.1
    autofs-5.0.2-percent-hack-fix.patch -> 1.1
    autofs-5.0.2-quell-mount-module-message.patch -> 1.1
    autofs-5.0.2-quote-exports-fix-fix.patch -> 1.1
    autofs-5.0.2-quote-exports-fix.patch -> 1.1
    autofs-5.0.2-quote-exports.patch -> 1.1
    autofs-5.0.2-quoted-slash-alone.patch -> 1.1
    autofs-5.0.2-random-selection-fix.patch -> 1.1
    autofs-5.0.2-remove-unsed-export-validation-code.patch -> 1.1
    autofs-5.0.2-report-failed-lookups.patch -> 1.1
    autofs-5.0.2-reread-config-on-hup.patch -> 1.1
    autofs-5.0.2-singleton-host-list.patch -> 1.1
    autofs-5.0.2-start-pipe-buff-size.patch -> 1.1
    autofs-5.0.2-submount-deadlock.patch -> 1.1
    autofs-5.0.2-swallow-null-macro.patch -> 1.1
    autofs-5.0.2-timeout-option-parse-fix.patch -> 1.1

62 files changed:
autofs-5.0.2-add-ferror-check.patch [new file with mode: 0644]
autofs-5.0.2-add-krb5-include.patch [new file with mode: 0644]
autofs-5.0.2-add-ldap-schema-discovery-fix-2.patch [new file with mode: 0644]
autofs-5.0.2-add-ldap-schema-discovery-fix.patch [new file with mode: 0644]
autofs-5.0.2-add-ldap-schema-discovery.patch [new file with mode: 0644]
autofs-5.0.2-add-missing-multi-support.patch [new file with mode: 0644]
autofs-5.0.2-add-multi-nsswitch-lookup.patch [new file with mode: 0644]
autofs-5.0.2-add-multiple-server-selection-option-fix.patch [new file with mode: 0644]
autofs-5.0.2-add-multiple-server-selection-option.patch [new file with mode: 0644]
autofs-5.0.2-autofs-5-typo.patch [new file with mode: 0644]
autofs-5.0.2-bad-proto-init.patch [new file with mode: 0644]
autofs-5.0.2-basedn-with-spaces-fix-2.patch [new file with mode: 0644]
autofs-5.0.2-basedn-with-spaces-fix.patch [new file with mode: 0644]
autofs-5.0.2-basedn-with-spaces.patch [new file with mode: 0644]
autofs-5.0.2-check-auto_master.patch [new file with mode: 0644]
autofs-5.0.2-check-mtab-updated-fix.patch [new file with mode: 0644]
autofs-5.0.2-check-mtab-updated.patch [new file with mode: 0644]
autofs-5.0.2-cleanup-krb5-comment.patch [new file with mode: 0644]
autofs-5.0.2-consistent-random-selection-option-name.patch [new file with mode: 0644]
autofs-5.0.2-default-nsswitch.patch [new file with mode: 0644]
autofs-5.0.2-dont-fail-on-empty-master-fix.patch [new file with mode: 0644]
autofs-5.0.2-dont-fail-on-empty-master.patch [new file with mode: 0644]
autofs-5.0.2-dynamic-logging-fixes.patch [new file with mode: 0644]
autofs-5.0.2-dynamic-logging-non-sasl.patch [new file with mode: 0644]
autofs-5.0.2-dynamic-logging.patch [new file with mode: 0644]
autofs-5.0.2-external-cred-cache.patch [new file with mode: 0644]
autofs-5.0.2-fix-dnattr-parse.patch [new file with mode: 0644]
autofs-5.0.2-fix-largefile-dumbness.patch [new file with mode: 0644]
autofs-5.0.2-fix-mount-nfs-nosymlink.patch [new file with mode: 0644]
autofs-5.0.2-fix-nfs-version-in-get-supported-ver-and-cost.patch [new file with mode: 0644]
autofs-5.0.2-fix-off-by-one-lookup.patch [new file with mode: 0644]
autofs-5.0.2-fix-offset-dir-create.patch [new file with mode: 0644]
autofs-5.0.2-fix-recursive-loopback-mounts.patch [new file with mode: 0644]
autofs-5.0.2-foreground-logging.patch [new file with mode: 0644]
autofs-5.0.2-hi-res-time.patch [new file with mode: 0644]
autofs-5.0.2-hosts-nosuid-default.patch [new file with mode: 0644]
autofs-5.0.2-improve-server-unavail-fix.patch [new file with mode: 0644]
autofs-5.0.2-improve-server-unavail.patch [new file with mode: 0644]
autofs-5.0.2-instance-stale-mark.patch [new file with mode: 0644]
autofs-5.0.2-large-groups.patch [new file with mode: 0644]
autofs-5.0.2-ldap-check-star.patch [new file with mode: 0644]
autofs-5.0.2-ldap-percent-hack.patch [new file with mode: 0644]
autofs-5.0.2-ldap-schema-discovery-config-update.patch [new file with mode: 0644]
autofs-5.0.2-ldap-search-basedn-list.patch [new file with mode: 0644]
autofs-5.0.2-libxml2-workaround.patch [new file with mode: 0644]
autofs-5.0.2-log-map-reload.patch [new file with mode: 0644]
autofs-5.0.2-negative-timeout-update.patch [new file with mode: 0644]
autofs-5.0.2-percent-hack-fix.patch [new file with mode: 0644]
autofs-5.0.2-quell-mount-module-message.patch [new file with mode: 0644]
autofs-5.0.2-quote-exports-fix-fix.patch [new file with mode: 0644]
autofs-5.0.2-quote-exports-fix.patch [new file with mode: 0644]
autofs-5.0.2-quote-exports.patch [new file with mode: 0644]
autofs-5.0.2-quoted-slash-alone.patch [new file with mode: 0644]
autofs-5.0.2-random-selection-fix.patch [new file with mode: 0644]
autofs-5.0.2-remove-unsed-export-validation-code.patch [new file with mode: 0644]
autofs-5.0.2-report-failed-lookups.patch [new file with mode: 0644]
autofs-5.0.2-reread-config-on-hup.patch [new file with mode: 0644]
autofs-5.0.2-singleton-host-list.patch [new file with mode: 0644]
autofs-5.0.2-start-pipe-buff-size.patch [new file with mode: 0644]
autofs-5.0.2-submount-deadlock.patch [new file with mode: 0644]
autofs-5.0.2-swallow-null-macro.patch [new file with mode: 0644]
autofs-5.0.2-timeout-option-parse-fix.patch [new file with mode: 0644]

diff --git a/autofs-5.0.2-add-ferror-check.patch b/autofs-5.0.2-add-ferror-check.patch
new file mode 100644 (file)
index 0000000..3e4ca21
--- /dev/null
@@ -0,0 +1,134 @@
+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);
diff --git a/autofs-5.0.2-add-krb5-include.patch b/autofs-5.0.2-add-krb5-include.patch
new file mode 100644 (file)
index 0000000..eb20df7
--- /dev/null
@@ -0,0 +1,24 @@
+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 {
diff --git a/autofs-5.0.2-add-ldap-schema-discovery-fix-2.patch b/autofs-5.0.2-add-ldap-schema-discovery-fix-2.patch
new file mode 100644 (file)
index 0000000..058b2ee
--- /dev/null
@@ -0,0 +1,39 @@
+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 {
diff --git a/autofs-5.0.2-add-ldap-schema-discovery-fix.patch b/autofs-5.0.2-add-ldap-schema-discovery-fix.patch
new file mode 100644 (file)
index 0000000..ee2f9fa
--- /dev/null
@@ -0,0 +1,32 @@
+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);
diff --git a/autofs-5.0.2-add-ldap-schema-discovery.patch b/autofs-5.0.2-add-ldap-schema-discovery.patch
new file mode 100644 (file)
index 0000000..08c86a2
--- /dev/null
@@ -0,0 +1,662 @@
+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;
diff --git a/autofs-5.0.2-add-missing-multi-support.patch b/autofs-5.0.2-add-missing-multi-support.patch
new file mode 100644 (file)
index 0000000..b6c3940
--- /dev/null
@@ -0,0 +1,543 @@
+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;
diff --git a/autofs-5.0.2-add-multi-nsswitch-lookup.patch b/autofs-5.0.2-add-multi-nsswitch-lookup.patch
new file mode 100644 (file)
index 0000000..45e44b2
--- /dev/null
@@ -0,0 +1,485 @@
+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);
diff --git a/autofs-5.0.2-add-multiple-server-selection-option-fix.patch b/autofs-5.0.2-add-multiple-server-selection-option-fix.patch
new file mode 100644 (file)
index 0000000..1645716
--- /dev/null
@@ -0,0 +1,229 @@
+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) {
diff --git a/autofs-5.0.2-add-multiple-server-selection-option.patch b/autofs-5.0.2-add-multiple-server-selection-option.patch
new file mode 100644 (file)
index 0000000..ef9b3f9
--- /dev/null
@@ -0,0 +1,864 @@
+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.
diff --git a/autofs-5.0.2-autofs-5-typo.patch b/autofs-5.0.2-autofs-5-typo.patch
new file mode 100644 (file)
index 0000000..2bd1e00
--- /dev/null
@@ -0,0 +1,25 @@
+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
diff --git a/autofs-5.0.2-bad-proto-init.patch b/autofs-5.0.2-bad-proto-init.patch
new file mode 100644 (file)
index 0000000..ad8a44b
--- /dev/null
@@ -0,0 +1,43 @@
+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 {
diff --git a/autofs-5.0.2-basedn-with-spaces-fix-2.patch b/autofs-5.0.2-basedn-with-spaces-fix-2.patch
new file mode 100644 (file)
index 0000000..935010d
--- /dev/null
@@ -0,0 +1,29 @@
+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;
+       }
diff --git a/autofs-5.0.2-basedn-with-spaces-fix.patch b/autofs-5.0.2-basedn-with-spaces-fix.patch
new file mode 100644 (file)
index 0000000..935c553
--- /dev/null
@@ -0,0 +1,97 @@
+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) {
diff --git a/autofs-5.0.2-basedn-with-spaces.patch b/autofs-5.0.2-basedn-with-spaces.patch
new file mode 100644 (file)
index 0000000..d1eb8a8
--- /dev/null
@@ -0,0 +1,33 @@
+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;
+       }
diff --git a/autofs-5.0.2-check-auto_master.patch b/autofs-5.0.2-check-auto_master.patch
new file mode 100644 (file)
index 0000000..8c1d9d4
--- /dev/null
@@ -0,0 +1,77 @@
+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;
diff --git a/autofs-5.0.2-check-mtab-updated-fix.patch b/autofs-5.0.2-check-mtab-updated-fix.patch
new file mode 100644 (file)
index 0000000..e67cde1
--- /dev/null
@@ -0,0 +1,138 @@
+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;
diff --git a/autofs-5.0.2-check-mtab-updated.patch b/autofs-5.0.2-check-mtab-updated.patch
new file mode 100644 (file)
index 0000000..7b8dc92
--- /dev/null
@@ -0,0 +1,200 @@
+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;
diff --git a/autofs-5.0.2-cleanup-krb5-comment.patch b/autofs-5.0.2-cleanup-krb5-comment.patch
new file mode 100644 (file)
index 0000000..68f2b40
--- /dev/null
@@ -0,0 +1,39 @@
+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;
diff --git a/autofs-5.0.2-consistent-random-selection-option-name.patch b/autofs-5.0.2-consistent-random-selection-option-name.patch
new file mode 100644 (file)
index 0000000..4caf287
--- /dev/null
@@ -0,0 +1,48 @@
+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
diff --git a/autofs-5.0.2-default-nsswitch.patch b/autofs-5.0.2-default-nsswitch.patch
new file mode 100644 (file)
index 0000000..44792c6
--- /dev/null
@@ -0,0 +1,63 @@
+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);
+ }
diff --git a/autofs-5.0.2-dont-fail-on-empty-master-fix.patch b/autofs-5.0.2-dont-fail-on-empty-master-fix.patch
new file mode 100644 (file)
index 0000000..d0fca73
--- /dev/null
@@ -0,0 +1,122 @@
+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;
+       }
diff --git a/autofs-5.0.2-dont-fail-on-empty-master.patch b/autofs-5.0.2-dont-fail-on-empty-master.patch
new file mode 100644 (file)
index 0000000..cddbc6e
--- /dev/null
@@ -0,0 +1,25 @@
+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();
diff --git a/autofs-5.0.2-dynamic-logging-fixes.patch b/autofs-5.0.2-dynamic-logging-fixes.patch
new file mode 100644 (file)
index 0000000..d93538b
--- /dev/null
@@ -0,0 +1,385 @@
+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) {
diff --git a/autofs-5.0.2-dynamic-logging-non-sasl.patch b/autofs-5.0.2-dynamic-logging-non-sasl.patch
new file mode 100644 (file)
index 0000000..bcc179b
--- /dev/null
@@ -0,0 +1,26 @@
+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);
diff --git a/autofs-5.0.2-dynamic-logging.patch b/autofs-5.0.2-dynamic-logging.patch
new file mode 100644 (file)
index 0000000..130993e
--- /dev/null
@@ -0,0 +1,6224 @@
+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;
diff --git a/autofs-5.0.2-external-cred-cache.patch b/autofs-5.0.2-external-cred-cache.patch
new file mode 100644 (file)
index 0000000..2efe93f
--- /dev/null
@@ -0,0 +1,404 @@
+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
diff --git a/autofs-5.0.2-fix-dnattr-parse.patch b/autofs-5.0.2-fix-dnattr-parse.patch
new file mode 100644 (file)
index 0000000..6143eb4
--- /dev/null
@@ -0,0 +1,25 @@
+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;
+       }
diff --git a/autofs-5.0.2-fix-largefile-dumbness.patch b/autofs-5.0.2-fix-largefile-dumbness.patch
new file mode 100644 (file)
index 0000000..fc0eff3
--- /dev/null
@@ -0,0 +1,25 @@
+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
diff --git a/autofs-5.0.2-fix-mount-nfs-nosymlink.patch b/autofs-5.0.2-fix-mount-nfs-nosymlink.patch
new file mode 100644 (file)
index 0000000..2cb2233
--- /dev/null
@@ -0,0 +1,44 @@
+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" : "";
diff --git a/autofs-5.0.2-fix-nfs-version-in-get-supported-ver-and-cost.patch b/autofs-5.0.2-fix-nfs-version-in-get-supported-ver-and-cost.patch
new file mode 100644 (file)
index 0000000..6e084b4
--- /dev/null
@@ -0,0 +1,51 @@
+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);
diff --git a/autofs-5.0.2-fix-off-by-one-lookup.patch b/autofs-5.0.2-fix-off-by-one-lookup.patch
new file mode 100644 (file)
index 0000000..c02958e
--- /dev/null
@@ -0,0 +1,64 @@
+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;
diff --git a/autofs-5.0.2-fix-offset-dir-create.patch b/autofs-5.0.2-fix-offset-dir-create.patch
new file mode 100644 (file)
index 0000000..7d48c77
--- /dev/null
@@ -0,0 +1,214 @@
+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++;
diff --git a/autofs-5.0.2-fix-recursive-loopback-mounts.patch b/autofs-5.0.2-fix-recursive-loopback-mounts.patch
new file mode 100644 (file)
index 0000000..c7b693c
--- /dev/null
@@ -0,0 +1,34 @@
+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--) {
diff --git a/autofs-5.0.2-foreground-logging.patch b/autofs-5.0.2-foreground-logging.patch
new file mode 100644 (file)
index 0000000..a7963fe
--- /dev/null
@@ -0,0 +1,289 @@
+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);
diff --git a/autofs-5.0.2-hi-res-time.patch b/autofs-5.0.2-hi-res-time.patch
new file mode 100644 (file)
index 0000000..d85d518
--- /dev/null
@@ -0,0 +1,68 @@
+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)
diff --git a/autofs-5.0.2-hosts-nosuid-default.patch b/autofs-5.0.2-hosts-nosuid-default.patch
new file mode 100644 (file)
index 0000000..2dd2f26
--- /dev/null
@@ -0,0 +1,91 @@
+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
diff --git a/autofs-5.0.2-improve-server-unavail-fix.patch b/autofs-5.0.2-improve-server-unavail-fix.patch
new file mode 100644 (file)
index 0000000..b104e22
--- /dev/null
@@ -0,0 +1,31 @@
+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;
diff --git a/autofs-5.0.2-improve-server-unavail.patch b/autofs-5.0.2-improve-server-unavail.patch
new file mode 100644 (file)
index 0000000..bd42bf9
--- /dev/null
@@ -0,0 +1,212 @@
+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;
+       }
diff --git a/autofs-5.0.2-instance-stale-mark.patch b/autofs-5.0.2-instance-stale-mark.patch
new file mode 100644 (file)
index 0000000..a414ee7
--- /dev/null
@@ -0,0 +1,32 @@
+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);
+ }
diff --git a/autofs-5.0.2-large-groups.patch b/autofs-5.0.2-large-groups.patch
new file mode 100644 (file)
index 0000000..d811f5e
--- /dev/null
@@ -0,0 +1,142 @@
+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);
diff --git a/autofs-5.0.2-ldap-check-star.patch b/autofs-5.0.2-ldap-check-star.patch
new file mode 100644 (file)
index 0000000..2d83fcc
--- /dev/null
@@ -0,0 +1,34 @@
+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");
diff --git a/autofs-5.0.2-ldap-percent-hack.patch b/autofs-5.0.2-ldap-percent-hack.patch
new file mode 100644 (file)
index 0000000..85be59b
--- /dev/null
@@ -0,0 +1,190 @@
+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;
+                       }
diff --git a/autofs-5.0.2-ldap-schema-discovery-config-update.patch b/autofs-5.0.2-ldap-schema-discovery-config-update.patch
new file mode 100644 (file)
index 0000000..f268381
--- /dev/null
@@ -0,0 +1,38 @@
+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"
diff --git a/autofs-5.0.2-ldap-search-basedn-list.patch b/autofs-5.0.2-ldap-search-basedn-list.patch
new file mode 100644 (file)
index 0000000..8a8966e
--- /dev/null
@@ -0,0 +1,833 @@
+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
diff --git a/autofs-5.0.2-libxml2-workaround.patch b/autofs-5.0.2-libxml2-workaround.patch
new file mode 100644 (file)
index 0000000..6c6c120
--- /dev/null
@@ -0,0 +1,128 @@
+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);
diff --git a/autofs-5.0.2-log-map-reload.patch b/autofs-5.0.2-log-map-reload.patch
new file mode 100644 (file)
index 0000000..0fcb552
--- /dev/null
@@ -0,0 +1,38 @@
+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);
diff --git a/autofs-5.0.2-negative-timeout-update.patch b/autofs-5.0.2-negative-timeout-update.patch
new file mode 100644 (file)
index 0000000..23b02b5
--- /dev/null
@@ -0,0 +1,505 @@
+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"
diff --git a/autofs-5.0.2-percent-hack-fix.patch b/autofs-5.0.2-percent-hack-fix.patch
new file mode 100644 (file)
index 0000000..03130b4
--- /dev/null
@@ -0,0 +1,312 @@
+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);
diff --git a/autofs-5.0.2-quell-mount-module-message.patch b/autofs-5.0.2-quell-mount-module-message.patch
new file mode 100644 (file)
index 0000000..81244cd
--- /dev/null
@@ -0,0 +1,39 @@
+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",
diff --git a/autofs-5.0.2-quote-exports-fix-fix.patch b/autofs-5.0.2-quote-exports-fix-fix.patch
new file mode 100644 (file)
index 0000000..7617b8f
--- /dev/null
@@ -0,0 +1,113 @@
+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);
diff --git a/autofs-5.0.2-quote-exports-fix.patch b/autofs-5.0.2-quote-exports-fix.patch
new file mode 100644 (file)
index 0000000..ec45ebf
--- /dev/null
@@ -0,0 +1,34 @@
+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);
diff --git a/autofs-5.0.2-quote-exports.patch b/autofs-5.0.2-quote-exports.patch
new file mode 100644 (file)
index 0000000..d371d98
--- /dev/null
@@ -0,0 +1,71 @@
+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);
diff --git a/autofs-5.0.2-quoted-slash-alone.patch b/autofs-5.0.2-quoted-slash-alone.patch
new file mode 100644 (file)
index 0000000..5e31d6f
--- /dev/null
@@ -0,0 +1,26 @@
+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;
diff --git a/autofs-5.0.2-random-selection-fix.patch b/autofs-5.0.2-random-selection-fix.patch
new file mode 100644 (file)
index 0000000..4248e9b
--- /dev/null
@@ -0,0 +1,267 @@
+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);
diff --git a/autofs-5.0.2-remove-unsed-export-validation-code.patch b/autofs-5.0.2-remove-unsed-export-validation-code.patch
new file mode 100644 (file)
index 0000000..20440ea
--- /dev/null
@@ -0,0 +1,623 @@
+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) {
diff --git a/autofs-5.0.2-report-failed-lookups.patch b/autofs-5.0.2-report-failed-lookups.patch
new file mode 100644 (file)
index 0000000..3502384
--- /dev/null
@@ -0,0 +1,123 @@
+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;
diff --git a/autofs-5.0.2-reread-config-on-hup.patch b/autofs-5.0.2-reread-config-on-hup.patch
new file mode 100644 (file)
index 0000000..e581f32
--- /dev/null
@@ -0,0 +1,140 @@
+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) {
diff --git a/autofs-5.0.2-singleton-host-list.patch b/autofs-5.0.2-singleton-host-list.patch
new file mode 100644 (file)
index 0000000..8b65926
--- /dev/null
@@ -0,0 +1,57 @@
+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;
diff --git a/autofs-5.0.2-start-pipe-buff-size.patch b/autofs-5.0.2-start-pipe-buff-size.patch
new file mode 100644 (file)
index 0000000..45472f2
--- /dev/null
@@ -0,0 +1,40 @@
+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();
diff --git a/autofs-5.0.2-submount-deadlock.patch b/autofs-5.0.2-submount-deadlock.patch
new file mode 100644 (file)
index 0000000..ca575b8
--- /dev/null
@@ -0,0 +1,34 @@
+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
diff --git a/autofs-5.0.2-swallow-null-macro.patch b/autofs-5.0.2-swallow-null-macro.patch
new file mode 100644 (file)
index 0000000..2e71ad6
--- /dev/null
@@ -0,0 +1,36 @@
+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;
diff --git a/autofs-5.0.2-timeout-option-parse-fix.patch b/autofs-5.0.2-timeout-option-parse-fix.patch
new file mode 100644 (file)
index 0000000..d5dac87
--- /dev/null
@@ -0,0 +1,25 @@
+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);
This page took 1.106239 seconds and 4 git commands to generate.