From 3d5516234e46fbbd4ed2f13d8d575a944b8cb520 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pawe=C5=82=20Go=C5=82aszewski?= Date: Mon, 24 Dec 2007 11:25:02 +0000 Subject: [PATCH] - "few" official patches 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 --- autofs-5.0.2-add-ferror-check.patch | 134 + autofs-5.0.2-add-krb5-include.patch | 24 + ....0.2-add-ldap-schema-discovery-fix-2.patch | 39 + ...-5.0.2-add-ldap-schema-discovery-fix.patch | 32 + autofs-5.0.2-add-ldap-schema-discovery.patch | 662 ++ autofs-5.0.2-add-missing-multi-support.patch | 543 ++ autofs-5.0.2-add-multi-nsswitch-lookup.patch | 485 ++ ...multiple-server-selection-option-fix.patch | 229 + ...add-multiple-server-selection-option.patch | 864 +++ autofs-5.0.2-autofs-5-typo.patch | 25 + autofs-5.0.2-bad-proto-init.patch | 43 + autofs-5.0.2-basedn-with-spaces-fix-2.patch | 29 + autofs-5.0.2-basedn-with-spaces-fix.patch | 97 + autofs-5.0.2-basedn-with-spaces.patch | 33 + autofs-5.0.2-check-auto_master.patch | 77 + autofs-5.0.2-check-mtab-updated-fix.patch | 138 + autofs-5.0.2-check-mtab-updated.patch | 200 + autofs-5.0.2-cleanup-krb5-comment.patch | 39 + ...sistent-random-selection-option-name.patch | 48 + autofs-5.0.2-default-nsswitch.patch | 63 + ...-5.0.2-dont-fail-on-empty-master-fix.patch | 122 + autofs-5.0.2-dont-fail-on-empty-master.patch | 25 + autofs-5.0.2-dynamic-logging-fixes.patch | 385 + autofs-5.0.2-dynamic-logging-non-sasl.patch | 26 + autofs-5.0.2-dynamic-logging.patch | 6224 +++++++++++++++++ autofs-5.0.2-external-cred-cache.patch | 404 ++ autofs-5.0.2-fix-dnattr-parse.patch | 25 + autofs-5.0.2-fix-largefile-dumbness.patch | 25 + autofs-5.0.2-fix-mount-nfs-nosymlink.patch | 44 + ...ersion-in-get-supported-ver-and-cost.patch | 51 + autofs-5.0.2-fix-off-by-one-lookup.patch | 64 + autofs-5.0.2-fix-offset-dir-create.patch | 214 + ...-5.0.2-fix-recursive-loopback-mounts.patch | 34 + autofs-5.0.2-foreground-logging.patch | 289 + autofs-5.0.2-hi-res-time.patch | 68 + autofs-5.0.2-hosts-nosuid-default.patch | 91 + autofs-5.0.2-improve-server-unavail-fix.patch | 31 + autofs-5.0.2-improve-server-unavail.patch | 212 + autofs-5.0.2-instance-stale-mark.patch | 32 + autofs-5.0.2-large-groups.patch | 142 + autofs-5.0.2-ldap-check-star.patch | 34 + autofs-5.0.2-ldap-percent-hack.patch | 190 + ...-ldap-schema-discovery-config-update.patch | 38 + autofs-5.0.2-ldap-search-basedn-list.patch | 833 +++ autofs-5.0.2-libxml2-workaround.patch | 128 + autofs-5.0.2-log-map-reload.patch | 38 + autofs-5.0.2-negative-timeout-update.patch | 505 ++ autofs-5.0.2-percent-hack-fix.patch | 312 + autofs-5.0.2-quell-mount-module-message.patch | 39 + autofs-5.0.2-quote-exports-fix-fix.patch | 113 + autofs-5.0.2-quote-exports-fix.patch | 34 + autofs-5.0.2-quote-exports.patch | 71 + autofs-5.0.2-quoted-slash-alone.patch | 26 + autofs-5.0.2-random-selection-fix.patch | 267 + ...-remove-unsed-export-validation-code.patch | 623 ++ autofs-5.0.2-report-failed-lookups.patch | 123 + autofs-5.0.2-reread-config-on-hup.patch | 140 + autofs-5.0.2-singleton-host-list.patch | 57 + autofs-5.0.2-start-pipe-buff-size.patch | 40 + autofs-5.0.2-submount-deadlock.patch | 34 + autofs-5.0.2-swallow-null-macro.patch | 36 + autofs-5.0.2-timeout-option-parse-fix.patch | 25 + 62 files changed, 16018 insertions(+) create mode 100644 autofs-5.0.2-add-ferror-check.patch create mode 100644 autofs-5.0.2-add-krb5-include.patch create mode 100644 autofs-5.0.2-add-ldap-schema-discovery-fix-2.patch create mode 100644 autofs-5.0.2-add-ldap-schema-discovery-fix.patch create mode 100644 autofs-5.0.2-add-ldap-schema-discovery.patch create mode 100644 autofs-5.0.2-add-missing-multi-support.patch create mode 100644 autofs-5.0.2-add-multi-nsswitch-lookup.patch create mode 100644 autofs-5.0.2-add-multiple-server-selection-option-fix.patch create mode 100644 autofs-5.0.2-add-multiple-server-selection-option.patch create mode 100644 autofs-5.0.2-autofs-5-typo.patch create mode 100644 autofs-5.0.2-bad-proto-init.patch create mode 100644 autofs-5.0.2-basedn-with-spaces-fix-2.patch create mode 100644 autofs-5.0.2-basedn-with-spaces-fix.patch create mode 100644 autofs-5.0.2-basedn-with-spaces.patch create mode 100644 autofs-5.0.2-check-auto_master.patch create mode 100644 autofs-5.0.2-check-mtab-updated-fix.patch create mode 100644 autofs-5.0.2-check-mtab-updated.patch create mode 100644 autofs-5.0.2-cleanup-krb5-comment.patch create mode 100644 autofs-5.0.2-consistent-random-selection-option-name.patch create mode 100644 autofs-5.0.2-default-nsswitch.patch create mode 100644 autofs-5.0.2-dont-fail-on-empty-master-fix.patch create mode 100644 autofs-5.0.2-dont-fail-on-empty-master.patch create mode 100644 autofs-5.0.2-dynamic-logging-fixes.patch create mode 100644 autofs-5.0.2-dynamic-logging-non-sasl.patch create mode 100644 autofs-5.0.2-dynamic-logging.patch create mode 100644 autofs-5.0.2-external-cred-cache.patch create mode 100644 autofs-5.0.2-fix-dnattr-parse.patch create mode 100644 autofs-5.0.2-fix-largefile-dumbness.patch create mode 100644 autofs-5.0.2-fix-mount-nfs-nosymlink.patch create mode 100644 autofs-5.0.2-fix-nfs-version-in-get-supported-ver-and-cost.patch create mode 100644 autofs-5.0.2-fix-off-by-one-lookup.patch create mode 100644 autofs-5.0.2-fix-offset-dir-create.patch create mode 100644 autofs-5.0.2-fix-recursive-loopback-mounts.patch create mode 100644 autofs-5.0.2-foreground-logging.patch create mode 100644 autofs-5.0.2-hi-res-time.patch create mode 100644 autofs-5.0.2-hosts-nosuid-default.patch create mode 100644 autofs-5.0.2-improve-server-unavail-fix.patch create mode 100644 autofs-5.0.2-improve-server-unavail.patch create mode 100644 autofs-5.0.2-instance-stale-mark.patch create mode 100644 autofs-5.0.2-large-groups.patch create mode 100644 autofs-5.0.2-ldap-check-star.patch create mode 100644 autofs-5.0.2-ldap-percent-hack.patch create mode 100644 autofs-5.0.2-ldap-schema-discovery-config-update.patch create mode 100644 autofs-5.0.2-ldap-search-basedn-list.patch create mode 100644 autofs-5.0.2-libxml2-workaround.patch create mode 100644 autofs-5.0.2-log-map-reload.patch create mode 100644 autofs-5.0.2-negative-timeout-update.patch create mode 100644 autofs-5.0.2-percent-hack-fix.patch create mode 100644 autofs-5.0.2-quell-mount-module-message.patch create mode 100644 autofs-5.0.2-quote-exports-fix-fix.patch create mode 100644 autofs-5.0.2-quote-exports-fix.patch create mode 100644 autofs-5.0.2-quote-exports.patch create mode 100644 autofs-5.0.2-quoted-slash-alone.patch create mode 100644 autofs-5.0.2-random-selection-fix.patch create mode 100644 autofs-5.0.2-remove-unsed-export-validation-code.patch create mode 100644 autofs-5.0.2-report-failed-lookups.patch create mode 100644 autofs-5.0.2-reread-config-on-hup.patch create mode 100644 autofs-5.0.2-singleton-host-list.patch create mode 100644 autofs-5.0.2-start-pipe-buff-size.patch create mode 100644 autofs-5.0.2-submount-deadlock.patch create mode 100644 autofs-5.0.2-swallow-null-macro.patch create mode 100644 autofs-5.0.2-timeout-option-parse-fix.patch diff --git a/autofs-5.0.2-add-ferror-check.patch b/autofs-5.0.2-add-ferror-check.patch new file mode 100644 index 0000000..3e4ca21 --- /dev/null +++ b/autofs-5.0.2-add-ferror-check.patch @@ -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 index 0000000..eb20df7 --- /dev/null +++ b/autofs-5.0.2-add-krb5-include.patch @@ -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 + #include + #include ++#include + #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 index 0000000..058b2ee --- /dev/null +++ b/autofs-5.0.2-add-ldap-schema-discovery-fix-2.patch @@ -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 index 0000000..ee2f9fa --- /dev/null +++ b/autofs-5.0.2-add-ldap-schema-discovery-fix.patch @@ -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 index 0000000..08c86a2 --- /dev/null +++ b/autofs-5.0.2-add-ldap-schema-discovery.patch @@ -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 + #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 + + #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 index 0000000..b6c3940 --- /dev/null +++ b/autofs-5.0.2-add-missing-multi-support.patch @@ -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 + #include + #include ++#include + #include + + #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 map + %type options + %type dn +@@ -103,6 +107,7 @@ static int master_fprintf(FILE *, char *, ...); + %token NILL + %token SPACE + %token EQUAL ++%token MULTITYPE + %token MAPTYPE + %token DNSERVER + %token 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 + #include + #include ++#include + #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}) + { + {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}) + { + {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 index 0000000..45e44b2 --- /dev/null +++ b/autofs-5.0.2-add-multi-nsswitch-lookup.patch @@ -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 + #include + #include ++#include + + #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 index 0000000..1645716 --- /dev/null +++ b/autofs-5.0.2-add-multiple-server-selection-option-fix.patch @@ -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 index 0000000..ef9b3f9 --- /dev/null +++ b/autofs-5.0.2-add-multiple-server-selection-option.patch @@ -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 + #include + ++#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 ://[/] ++where 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 ++# ://[/] where 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 ++# ://[/] where 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 index 0000000..2bd1e00 --- /dev/null +++ b/autofs-5.0.2-autofs-5-typo.patch @@ -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 index 0000000..ad8a44b --- /dev/null +++ b/autofs-5.0.2-bad-proto-init.patch @@ -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 index 0000000..935010d --- /dev/null +++ b/autofs-5.0.2-basedn-with-spaces-fix-2.patch @@ -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 index 0000000..935c553 --- /dev/null +++ b/autofs-5.0.2-basedn-with-spaces-fix.patch @@ -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 index 0000000..d1eb8a8 --- /dev/null +++ b/autofs-5.0.2-basedn-with-spaces.patch @@ -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 index 0000000..8c1d9d4 --- /dev/null +++ b/autofs-5.0.2-check-auto_master.patch @@ -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 index 0000000..e67cde1 --- /dev/null +++ b/autofs-5.0.2-check-mtab-updated-fix.patch @@ -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 + #include + #include ++#include + + #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 index 0000000..7b8dc92 --- /dev/null +++ b/autofs-5.0.2-check-mtab-updated.patch @@ -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 index 0000000..68f2b40 --- /dev/null +++ b/autofs-5.0.2-cleanup-krb5-comment.patch @@ -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 index 0000000..4caf287 --- /dev/null +++ b/autofs-5.0.2-consistent-random-selection-option-name.patch @@ -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 index 0000000..44792c6 --- /dev/null +++ b/autofs-5.0.2-default-nsswitch.patch @@ -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 index 0000000..d0fca73 --- /dev/null +++ b/autofs-5.0.2-dont-fail-on-empty-master-fix.patch @@ -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 index 0000000..cddbc6e --- /dev/null +++ b/autofs-5.0.2-dont-fail-on-empty-master.patch @@ -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 index 0000000..d93538b --- /dev/null +++ b/autofs-5.0.2-dynamic-logging-fixes.patch @@ -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 index 0000000..bcc179b --- /dev/null +++ b/autofs-5.0.2-dynamic-logging-non-sasl.patch @@ -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 index 0000000..130993e --- /dev/null +++ b/autofs-5.0.2-dynamic-logging.patch @@ -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 index 0000000..2efe93f --- /dev/null +++ b/autofs-5.0.2-external-cred-cache.patch @@ -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/@. ++ ++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. + --> + + >= 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 index 0000000..c02958e --- /dev/null +++ b/autofs-5.0.2-fix-off-by-one-lookup.patch @@ -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 index 0000000..7d48c77 --- /dev/null +++ b/autofs-5.0.2-fix-offset-dir-create.patch @@ -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 index 0000000..c7b693c --- /dev/null +++ b/autofs-5.0.2-fix-recursive-loopback-mounts.patch @@ -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 index 0000000..a7963fe --- /dev/null +++ b/autofs-5.0.2-foreground-logging.patch @@ -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 index 0000000..d85d518 --- /dev/null +++ b/autofs-5.0.2-hi-res-time.patch @@ -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 index 0000000..2dd2f26 --- /dev/null +++ b/autofs-5.0.2-hosts-nosuid-default.patch @@ -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 index 0000000..b104e22 --- /dev/null +++ b/autofs-5.0.2-improve-server-unavail-fix.patch @@ -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 index 0000000..bd42bf9 --- /dev/null +++ b/autofs-5.0.2-improve-server-unavail.patch @@ -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 index 0000000..a414ee7 --- /dev/null +++ b/autofs-5.0.2-instance-stale-mark.patch @@ -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 index 0000000..d811f5e --- /dev/null +++ b/autofs-5.0.2-large-groups.patch @@ -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 index 0000000..2d83fcc --- /dev/null +++ b/autofs-5.0.2-ldap-check-star.patch @@ -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 index 0000000..85be59b --- /dev/null +++ b/autofs-5.0.2-ldap-percent-hack.patch @@ -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 index 0000000..f268381 --- /dev/null +++ b/autofs-5.0.2-ldap-schema-discovery-config-update.patch @@ -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 index 0000000..8a8966e --- /dev/null +++ b/autofs-5.0.2-ldap-search-basedn-list.patch @@ -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 index 0000000..6c6c120 --- /dev/null +++ b/autofs-5.0.2-libxml2-workaround.patch @@ -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 + + #include "automount.h" ++#ifdef LIBXML2_WORKAROUND ++#include ++#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 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 index 0000000..0fcb552 --- /dev/null +++ b/autofs-5.0.2-log-map-reload.patch @@ -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 index 0000000..23b02b5 --- /dev/null +++ b/autofs-5.0.2-negative-timeout-update.patch @@ -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 map + %type 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 " ++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 , \-\-negative\-timeout " ++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 index 0000000..03130b4 --- /dev/null +++ b/autofs-5.0.2-percent-hack-fix.patch @@ -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 index 0000000..81244cd --- /dev/null +++ b/autofs-5.0.2-quell-mount-module-message.patch @@ -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 index 0000000..7617b8f --- /dev/null +++ b/autofs-5.0.2-quote-exports-fix-fix.patch @@ -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 index 0000000..ec45ebf --- /dev/null +++ b/autofs-5.0.2-quote-exports-fix.patch @@ -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 index 0000000..d371d98 --- /dev/null +++ b/autofs-5.0.2-quote-exports.patch @@ -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 index 0000000..5e31d6f --- /dev/null +++ b/autofs-5.0.2-quoted-slash-alone.patch @@ -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 index 0000000..4248e9b --- /dev/null +++ b/autofs-5.0.2-random-selection-fix.patch @@ -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 map + %type 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 index 0000000..20440ea --- /dev/null +++ b/autofs-5.0.2-remove-unsed-export-validation-code.patch @@ -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 , 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 index 0000000..3502384 --- /dev/null +++ b/autofs-5.0.2-report-failed-lookups.patch @@ -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 index 0000000..e581f32 --- /dev/null +++ b/autofs-5.0.2-reread-config-on-hup.patch @@ -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 index 0000000..8b65926 --- /dev/null +++ b/autofs-5.0.2-singleton-host-list.patch @@ -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 index 0000000..45472f2 --- /dev/null +++ b/autofs-5.0.2-start-pipe-buff-size.patch @@ -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 index 0000000..ca575b8 --- /dev/null +++ b/autofs-5.0.2-submount-deadlock.patch @@ -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 index 0000000..2e71ad6 --- /dev/null +++ b/autofs-5.0.2-swallow-null-macro.patch @@ -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 index 0000000..d5dac87 --- /dev/null +++ b/autofs-5.0.2-timeout-option-parse-fix.patch @@ -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); -- 2.44.0