diff --git a/postfix/.indent.pro b/postfix/.indent.pro
index 789741ca4..32e60db68 100644
--- a/postfix/.indent.pro
+++ b/postfix/.indent.pro
@@ -186,6 +186,7 @@
-TNAME_CODE
-TNAME_MASK
-TNBBIO
+-TPC_MASTER_ENT
-TPC_SERVICE_DEF
-TPC_STRING_NV
-TPEER_NAME
diff --git a/postfix/HISTORY b/postfix/HISTORY
index 5dcb4d224..1febd6715 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -17109,3 +17109,13 @@ Apologies for any names omitted.
Cleanup: "postconf" commands in postfix-install needed to
be updated before master.cf was installed. Reported by
Sahil Tandon. File: postfix-install.
+
+20111120
+
+ Cleanup: support for parameter name spaces for master.cf
+ entries. With this, postconf should no longer log false
+ warnings for "-o user-defined-name=value" in master.cf. As
+ a benefit, it will warn for user-defined parameters with
+ "name=value" entries that are unused because they are hidden
+ by master.cf "-o name=value" entries with the same parameter
+ name. File: postconf/postconf.c.
diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES
index 6e8ce5ad1..2b03dba0b 100644
--- a/postfix/RELEASE_NOTES
+++ b/postfix/RELEASE_NOTES
@@ -14,6 +14,14 @@ specifies the release date of a stable release or snapshot release.
If you upgrade from Postfix 2.7 or earlier, read RELEASE_NOTES-2.8
before proceeding.
+Major changes with snapshot 20111120
+====================================
+
+Eliminated the postconf limitation documented on 20111113 as "lack
+of support for per-service parameter name spaces in master.cf,
+meaning that "-o user-defined-name=value" always results in an
+"unused parameter" warning".
+
Major changes with snapshot 20111118
====================================
diff --git a/postfix/html/postconf.1.html b/postfix/html/postconf.1.html
index 0c4ed0a04..b966b6a62 100644
--- a/postfix/html/postconf.1.html
+++ b/postfix/html/postconf.1.html
@@ -22,12 +22,14 @@ POSTCONF(1) POSTCONF(1)
postconf [-fMv] [-c config_dir] [service ...]
+ Managing bounce message templates:
+
+ postconf [-btv] [-c config_dir] [template_file]
+
Managing other configuration:
postconf [-aAlmv] [-c config_dir]
- postconf [-btv] [-c config_dir] [template_file]
-
DESCRIPTION
By default, the postconf(1) command displays the values of
main.cf configuration parameters, and warns about possible
@@ -133,7 +135,7 @@ POSTCONF(1) POSTCONF(1)
human readability.
If service ... is specified, only the matching ser-
- vices will be output. For example, a service of
+ vices will be output. For example, a service of
inet will match all services that listen on the
network.
@@ -287,29 +289,23 @@ POSTCONF(1) POSTCONF(1)
DIAGNOSTICS
Problems are reported to the standard error stream.
-BUGS
- postconf(1) may log "unused parameter" warnings for mas-
- ter.cf entries with "-o user-defined-name=value".
- Addressing this limitation requires support for per-ser-
- vice parameter name spaces.
-
ENVIRONMENT
MAIL_CONFIG
Directory with Postfix configuration files.
CONFIGURATION PARAMETERS
- The following main.cf parameters are especially relevant
+ The following main.cf parameters are especially relevant
to this program.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
postconf(5) for more details including examples.
config_directory (see 'postconf -d' output)
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
bounce_template_file (empty)
- Pathname of a configuration file with bounce mes-
+ Pathname of a configuration file with bounce mes-
sage templates.
FILES
@@ -324,7 +320,7 @@ POSTCONF(1) POSTCONF(1)
DATABASE_README, Postfix lookup table overview
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/man/man1/postconf.1 b/postfix/man/man1/postconf.1
index e572dd5a8..fbcf98f69 100644
--- a/postfix/man/man1/postconf.1
+++ b/postfix/man/man1/postconf.1
@@ -25,11 +25,13 @@ Postfix configuration utility
\fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR]
[\fIservice ...\fR]
+\fBManaging bounce message templates:\fR
+
+\fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
+
\fBManaging other configuration:\fR
\fBpostconf\fR [\fB-aAlmv\fR] [\fB-c \fIconfig_dir\fR]
-
-\fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
.SH DESCRIPTION
.ad
.fi
@@ -124,7 +126,7 @@ file contents. Use \fB-Mf\fR to fold long lines for human
readability.
If \fIservice ...\fR is specified, only the matching services
-will be output. For example, a \fIservice\fB of \fBinet\fR
+will be output. For example, a \fIservice\fR of \fBinet\fR
will match all services that listen on the network.
Specify zero or more arguments, each with a \fIservice-type\fR
@@ -244,13 +246,6 @@ This feature is available with Postfix 2.6 and later.
.ad
.fi
Problems are reported to the standard error stream.
-.SH BUGS
-.ad
-.fi
-\fBpostconf\fR(1) may log "unused parameter" warnings for
-\fBmaster.cf\fR entries with "-o user-defined-name=value".
-Addressing this limitation requires support for per-service
-parameter name spaces.
.SH "ENVIRONMENT"
.na
.nf
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index f92a34a82..07aee6e5d 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20111119"
+#define MAIL_RELEASE_DATE "20111120"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
diff --git a/postfix/src/postconf/Makefile.in b/postfix/src/postconf/Makefile.in
index 63701be54..ca31397cd 100644
--- a/postfix/src/postconf/Makefile.in
+++ b/postfix/src/postconf/Makefile.in
@@ -36,7 +36,8 @@ Makefile: Makefile.in
test: $(TESTPROG)
-tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11
+tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \
+ test12 test13 test14 test15
root_tests:
@@ -100,9 +101,7 @@ test4: $(PROG) test4.ref
rm -f main.cf master.cf test4.tmp
# Define one user-defined parameter with name=value in master.cf,
-# validate it with known_parameter=$name in master.cf. Currently,
-# user-defined parameter definitions in master.cf are not recognized
-# as definitions, and result in an "unused parameter" warning.
+# validate it with known_parameter=$name in master.cf.
test5: $(PROG) test5.ref
rm -f main.cf master.cf
@@ -169,6 +168,58 @@ test11: $(PROG) test11.ref
diff test11.ref test11.tmp
rm -f main.cf master.cf test11.tmp
+# Duplicate service entry.
+
+test12: $(PROG) test12.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo bar=yes >> main.cf
+ echo foo inet - n n - 0 spawn >> master.cf
+ echo ' -o always_bcc=$$bar -o' >> master.cf
+ echo foo inet - n n - 0 spawn >> master.cf
+ echo ' -o always_bcc=$$bar -o' >> master.cf
+ ./$(PROG) -c . -M >test12.tmp 2>&1
+ diff test12.ref test12.tmp
+ rm -f main.cf master.cf test12.tmp
+
+# Define parameter with restriction_classes in master.cf, validate in main.cf.
+
+test13: $(PROG) test13.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo bar=yes >> main.cf
+ echo baz=xx >> main.cf
+ echo foo inet - n n - 0 spawn >> master.cf
+ echo ' -o smtpd_restriction_classes=bar' >> master.cf
+ ./$(PROG) -nc . >test13.tmp 2>&1
+ diff test13.ref test13.tmp
+ rm -f main.cf master.cf test13.tmp
+
+# Define parameter with restriction_classes in main.cf, validate in master.cf.
+
+test14: $(PROG) test14.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo smtpd_restriction_classes=bar >> main.cf
+ echo foo inet - n n - 0 spawn >> master.cf
+ echo ' -o bar=yes -o baz=xx' >> master.cf
+ ./$(PROG) -nc . >test14.tmp 2>&1
+ diff test14.ref test14.tmp
+ rm -f main.cf master.cf test14.tmp
+
+# Define two parameters, one is hidden by master.cf.
+
+test15: $(PROG) test15.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo bar=xx >> main.cf
+ echo baz=yy >> main.cf
+ echo foo inet - n n - 0 spawn >> master.cf
+ echo ' -o bar=yes -o always_bcc=$$bar$$baz' >> master.cf
+ ./$(PROG) -nc . >test15.tmp 2>&1
+ diff test15.ref test15.tmp
+ rm -f main.cf master.cf test15.tmp
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c
index ac96720ca..6c8108db2 100644
--- a/postfix/src/postconf/postconf.c
+++ b/postfix/src/postconf/postconf.c
@@ -21,11 +21,13 @@
/* \fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR]
/* [\fIservice ...\fR]
/*
+/* \fBManaging bounce message templates:\fR
+/*
+/* \fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
+/*
/* \fBManaging other configuration:\fR
/*
/* \fBpostconf\fR [\fB-aAlmv\fR] [\fB-c \fIconfig_dir\fR]
-/*
-/* \fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
/* DESCRIPTION
/* By default, the \fBpostconf\fR(1) command displays the
/* values of \fBmain.cf\fR configuration parameters, and warns
@@ -118,7 +120,7 @@
/* readability.
/*
/* If \fIservice ...\fR is specified, only the matching services
-/* will be output. For example, a \fIservice\fB of \fBinet\fR
+/* will be output. For example, a \fIservice\fR of \fBinet\fR
/* will match all services that listen on the network.
/*
/* Specify zero or more arguments, each with a \fIservice-type\fR
@@ -236,11 +238,6 @@
/* This feature is available with Postfix 2.6 and later.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
-/* BUGS
-/* \fBpostconf\fR(1) may log "unused parameter" warnings for
-/* \fBmaster.cf\fR entries with "-o user-defined-name=value".
-/* Addressing this limitation requires support for per-service
-/* parameter name spaces.
/* ENVIRONMENT
/* .ad
/* .fi
@@ -358,7 +355,7 @@
#define FOLD_LINE (1<<11) /* fold long *.cf entries */
/*
- * Lookup table for in-core parameter info.
+ * Lookup table for global parameter info.
*
* XXX Change the value pointers from table indices into pointers to parameter
* objects with print methods.
@@ -366,13 +363,21 @@
HTABLE *param_table;
/*
- * Lookup table for master.cf info.
- *
- * XXX Replace by data structures with per-entry hashes for "-o name=value", so
- * that we can properly handle name=value definitions in per-service name
- * spaces.
+ * Global restriction_classes hash.
*/
-static ARGV **master_table;
+HTABLE *rest_class_table;
+
+ /*
+ * Lookup table for master.cf info. The table is null-terminated.
+ */
+typedef struct {
+ char *name_space; /* service.type, parameter name space */
+ ARGV *argv; /* terminator, or master.cf fields */
+ DICT *all_params; /* all name=value entries */
+ HTABLE *valid_names; /* "blessed" parameters */
+} PC_MASTER_ENT;
+
+static PC_MASTER_ENT *master_table;
/*
* Support for built-in parameters: declarations generated by scanning
@@ -458,24 +463,25 @@ static ssize_t serv_param_tablen;
*
* There are three categories of known parameters: built-in, service-defined
* (see previous comment), and valid user-defined. In addition there are
- * multiple name spaces: the global main.cf name space, and the per-service
- * name space of each master.cf entry.
+ * multiple name spaces: the global main.cf name space, and the local name
+ * space of each master.cf entry.
*
* There are two categories of valid user-defined parameters:
*
- * - Parameters whose name appears in the value of smtpd_restriction_classes in
- * main.cf, and whose name has a "name=value" entry in main.cf (todo:
- * support for creating names with "-o smtpd_restriction_classes=name"
- * within a master.cf per-service name space).
+ * - Parameters whose user-defined-name appears in the value of
+ * smtpd_restriction_classes in main.cf or master.cf, and that have a
+ * "user-defined-name=value" entry in main.cf or master.cf.
*
- * - Parameters whose $name (macro expansion) appears in the value of a
- * "name=value" entry in main.cf or master.cf of a "known" parameter, and
- * whose name has a "name=value" entry in main.cf (todo: master.cf).
+ * - Parameters whose $user-defined-name appears in the value of a "name=value"
+ * entry in main.cf or master.cf, and whose user-defined-name has a
+ * "name=value" entry in main.cf or master.cf.
*
- * All other user-defined parameters are invalid. We currently log a warning
- * for "name=value" entries in main.cf or master.cf whose $name does not
- * appear in the value of a main.cf or master.cf "name=value" entry of a
- * "known" parameter.
+ * Other user-defined parameters are flagged as "unused".
+ */
+
+ /*
+ * Global-scope valid user-defined parameter names. The local-scope valid
+ * user-defined names are kept in the table with master.cf entries.
*/
static char **user_param_table;
static ssize_t user_param_tablen;
@@ -820,10 +826,12 @@ static void read_master(void)
path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
/*
- * We can't use the master_ent routines in their current form. They
- * convert everything to internal form, and they skip disabled services.
- * We need to be able to show default fields as "-", and we need to know
- * about all service names so that we can generate service-dependent
+ * We can't use the master daemon's master_ent routines in their current
+ * form. They convert everything to internal form, and they skip disabled
+ * services.
+ *
+ * The postconf command needs to show default fields as "-", and needs to
+ * know about all service names so that it can generate service-dependent
* parameter names (transport-dependent etc.).
*/
#define MASTER_BLANKS " \t\r\n" /* XXX */
@@ -832,7 +840,7 @@ static void read_master(void)
/*
* Initialize the in-memory master table.
*/
- master_table = (ARGV **) mymalloc(sizeof(*master_table));
+ master_table = (PC_MASTER_ENT *) mymalloc(sizeof(*master_table));
/*
* Skip blank lines and comment lines.
@@ -840,14 +848,23 @@ static void read_master(void)
if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
msg_fatal("open %s: %m", path);
while (readlline(buf, fp, &line_count) != 0) {
- master_table = (ARGV **) myrealloc((char *) master_table,
+ master_table = (PC_MASTER_ENT *) myrealloc((char *) master_table,
(entry_count + 2) * sizeof(*master_table));
argv = argv_split(STR(buf), MASTER_BLANKS);
if (argv->argc < MASTER_FIELD_COUNT)
msg_fatal("file %s: line %d: bad field count", path, line_count);
- master_table[entry_count++] = argv;
+ master_table[entry_count].name_space =
+ concatenate(argv->argv[0], ".", argv->argv[1], (char *) 0);
+ master_table[entry_count].argv = argv;
+ master_table[entry_count].valid_names = 0;
+ master_table[entry_count].all_params = 0;
+ entry_count += 1;
}
- master_table[entry_count] = 0;
+
+ /*
+ * Null-terminate the master table and clean up.
+ */
+ master_table[entry_count].argv = 0;
vstream_fclose(fp);
myfree(path);
vstring_free(buf);
@@ -938,7 +955,7 @@ static void add_service_parameters(void)
const PC_STRING_NV *sp;
const char *progname;
const char *service;
- ARGV **argvp;
+ PC_MASTER_ENT *masterp;
ARGV *argv;
const PC_SERVICE_DEF *sd;
@@ -952,7 +969,7 @@ static void add_service_parameters(void)
* Extract service names from master.cf and generate service parameter
* information.
*/
- for (argvp = master_table; (argv = *argvp) != 0; argvp++) {
+ for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) {
/*
* Add service parameters for message delivery transports or spawn
@@ -978,118 +995,152 @@ static void add_service_parameters(void)
htable_enter(param_table, sp->name, (char *) sp);
}
-/* add_user_parameter - add one user-defined parameter name */
-
-static void add_user_parameter(const char *name)
-{
- /* XXX Merge this with check_parameter_value() */
- user_param_table = (char **)
- myrealloc((char *) user_param_table,
- (user_param_tablen + 1) * sizeof(*user_param_table));
- user_param_table[user_param_tablen] = mystrdup(name);
- user_param_tablen += 1;
-}
-
-/* scan_user_parameter_value - extract macro names from parameter value */
+/* scan_user_parameter_value - examine macro names in parameter value */
#define NO_SCAN_RESULT ((VSTRING *) 0)
#define NO_SCAN_FILTER ((char *) 0)
#define NO_SCAN_MODE (0)
-#define NO_SCAN_CONTEXT ((char *) 0)
-#define scan_user_parameter_value(value) do { \
+#define scan_user_parameter_value(value, context) do { \
(void) mac_expand(NO_SCAN_RESULT, (value), MAC_EXP_FLAG_SCAN, \
- NO_SCAN_FILTER, check_user_parameter, NO_SCAN_CONTEXT); \
+ NO_SCAN_FILTER, check_user_parameter, (context)); \
} while (0)
-/* check_user_parameter - try to promote user-defined parameter */
+/* check_user_parameter - promote user-defined name if it has name=value */
static const char *check_user_parameter(const char *mac_name,
int unused_mode,
- char *unused_context)
+ char *context)
{
- const char *mac_value;
+ PC_MASTER_ENT *local_scope = (PC_MASTER_ENT *) context;
/*
* Promote only user-defined parameters with an explicit "name=value"
- * definition in main.cf (todo: master.cf). Do not promote parameters
- * whose name appears only as a macro expansion; this is how Postfix
- * implements backwards compatibility after a feature name change.
+ * definition. If the name=value exists in the local scope, update the
+ * local "valid" parameter name table, otherwise update the global one.
*
- * Skip parameters that are already in the param_table hash.
+ * Do not promote user-defined parameters whose name appears only as macro
+ * expansion; this is how Postfix implements backwards compatibility
+ * after a feature name change.
+ *
+ * Skip global names that are already in the param_table hash.
*/
- if (htable_locate(param_table, mac_name) == 0) {
- mac_value = mail_conf_lookup(mac_name);
- if (mac_value != 0) {
- add_user_parameter(mac_name);
- /* Promote parameter names recursively. */
- scan_user_parameter_value(mac_value);
+ if (local_scope && dict_get(local_scope->all_params, mac_name)) {
+ if (htable_locate(local_scope->valid_names, mac_name) == 0)
+ htable_enter(local_scope->valid_names, mac_name, "");
+ } else if (htable_locate(param_table, mac_name) == 0) {
+ if (mail_conf_lookup(mac_name) != 0) {
+ user_param_table = (char **)
+ myrealloc((char *) user_param_table,
+ (user_param_tablen + 1) * sizeof(*user_param_table));
+ user_param_table[user_param_tablen] = mystrdup(mac_name);
+ user_param_tablen += 1;
}
}
return (0);
}
+/* pc_lookup_eval - generalized mail_conf_lookup_eval */
+
+static const char *pc_lookup_eval(const char *dict_name, const char *name)
+{
+ const char *value;
+
+#define RECURSIVE 1
+
+ if ((value = dict_lookup(dict_name, name)) != 0)
+ value = dict_eval(dict_name, value, RECURSIVE);
+ return (value);
+}
+
+/* scan_user_parameter_namespace - scan parameters in name space */
+
+static void scan_user_parameter_namespace(const char *dict_name,
+ PC_MASTER_ENT *local_scope)
+{
+ const char *myname = "scan_user_parameter_namespace";
+ const char *class_list;
+ char *saved_class_list;
+ char *cp;
+ DICT *dict;
+ char *param_name;
+ int how;
+ const char *cparam_name;
+ const char *cparam_value;
+
+ /*
+ * Add parameters whose names are defined with smtpd_restriction_classes,
+ * but only if they have a "name=value" entry. If we are in the global
+ * scope, update the global restriction class name table, so that we can
+ * query the table from within a local master.cf name space.
+ */
+ if ((class_list = pc_lookup_eval(dict_name, VAR_REST_CLASSES)) != 0) {
+ cp = saved_class_list = mystrdup(class_list);
+ while ((param_name = mystrtok(&cp, ", \t\r\n")) != 0) {
+ if (local_scope == 0
+ && htable_locate(rest_class_table, param_name) == 0)
+ htable_enter(rest_class_table, param_name, "");
+ check_user_parameter(param_name, NO_SCAN_MODE,
+ (char *) local_scope);
+ }
+ myfree(saved_class_list);
+ }
+
+ /*
+ * For all "name=value" instances: a) if the scope is local and the name
+ * appears in the global restriction class table, flag the name as
+ * "valid" in the local scope; b) scan the value for macro expansions of
+ * unknown parameter names, and flag those parameter names as "valid" if
+ * they have a "name=value" entry.
+ */
+ if ((dict = dict_handle(dict_name)) == 0)
+ msg_panic("%s: parameter dictionary %s not found",
+ myname, dict_name);
+ if (dict->sequence == 0)
+ msg_panic("%s: parameter dictionary %s has no iterator",
+ myname, dict_name);
+ for (how = DICT_SEQ_FUN_FIRST;
+ dict->sequence(dict, how, &cparam_name, &cparam_value) == 0;
+ how = DICT_SEQ_FUN_NEXT) {
+ if (local_scope != 0
+ && htable_locate(local_scope->valid_names, cparam_name) == 0
+ && htable_locate(rest_class_table, cparam_name) != 0)
+ htable_enter(local_scope->valid_names, cparam_name, "");
+ scan_user_parameter_value(cparam_value, (char *) local_scope);
+ }
+}
+
/* add_user_parameters - add parameters with user-defined names */
static void add_user_parameters(void)
{
- const char *class_list;
- char *saved_class_list;
- char *cp;
- const char *cparam_value;
- HTABLE_INFO **ht_info;
- HTABLE_INFO **ht;
- ARGV **argvp;
+ PC_MASTER_ENT *masterp;
ARGV *argv;
char *arg;
int field;
char *saved_arg;
char *param_name;
char *param_value;
+ DICT *dict;
char **up;
/*
- * Initialize the table with user-defined parameter names and values.
+ * Initialize the global table with user-defined parameter names, and the
+ * table with global restriction class names.
*/
user_param_table = (char **) mymalloc(1);
user_param_tablen = 0;
+ rest_class_table = htable_create(1);
/*
- * Add parameters whose names are defined with smtpd_restriction_classes,
- * but only if they have a "name=value" entry in main.cf.
- *
- * XXX It is possible that a user-defined parameter is defined in master.cf
- * with "-o smtpd_restriction_classes=name -o name=value". This requires
- * name space support for master.cf entries. Without this, we always log
- * "unused parameter" warnings for "-o user-defined-name=value" entries.
+ * Scan the explicit name=value entries in the global name space.
*/
- if ((class_list = mail_conf_lookup_eval(VAR_REST_CLASSES)) != 0) {
- cp = saved_class_list = mystrdup(class_list);
- while ((param_name = mystrtok(&cp, ", \t\r\n")) != 0)
- check_user_parameter(param_name, NO_SCAN_MODE, NO_SCAN_CONTEXT);
- myfree(saved_class_list);
- }
+ scan_user_parameter_namespace(CONFIG_DICT, (PC_MASTER_ENT *) 0);
/*
- * Parse the "name=value" instances in main.cf of built-in and service
- * parameters only, look for macro expansions of unknown parameter names,
- * and flag those parameter names as "known" if they have a "name=value"
- * entry in main.cf. Recursively apply the procedure to the values of
- * newly-flagged parameters.
+ * Scan the "-o parameter=value" instances in each master.cf name space.
*/
- for (ht_info = ht = htable_list(param_table); *ht; ht++)
- if ((cparam_value = mail_conf_lookup(ht[0]->key)) != 0)
- scan_user_parameter_value(cparam_value);
- myfree((char *) ht_info);
-
- /*
- * Parse all "-o parameter=value" instances in master.cf, look for macro
- * expansions of unknown parameter names, and flag those parameter names
- * as "known" if they have a "name=value" entry in main.cf (XXX todo: in
- * master.cf; without master.cf name space support we always log "unused
- * parameter" warnings for "-o user-defined-name=value" entries).
- */
- for (argvp = master_table; (argv = *argvp) != 0; argvp++) {
+ for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) {
for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) {
arg = argv->argv[field];
if (arg[0] != '-')
@@ -1097,11 +1148,16 @@ static void add_user_parameters(void)
if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) {
saved_arg = mystrdup(arg);
if (split_nameval(saved_arg, ¶m_name, ¶m_value) == 0)
- scan_user_parameter_value(param_value);
+ dict_update(masterp->name_space, param_name, param_value);
myfree(saved_arg);
field += 1;
}
}
+ if ((dict = dict_handle(masterp->name_space)) != 0) {
+ masterp->all_params = dict;
+ masterp->valid_names = htable_create(1);
+ scan_user_parameter_namespace(masterp->name_space, masterp);
+ }
}
/*
@@ -1756,35 +1812,25 @@ static void print_master_line(int mode, ARGV *argv)
static void show_master(int mode, char **filters)
{
- ARGV **argvp;
+ PC_MASTER_ENT *masterp;
ARGV *argv;
- VSTRING *service_name = 0;
ARGV *service_filter = 0;
/*
* Initialize the service filter.
*/
- if (filters[0]) {
- service_name = vstring_alloc(10);
+ if (filters[0])
service_filter = match_service_init_argv(filters);
- }
/*
* Iterate over the master table.
*/
- for (argvp = master_table; (argv = *argvp) != 0; argvp++) {
- if (service_filter) {
- vstring_sprintf(service_name, "%s.%s",
- argv->argv[0], argv->argv[1]);
- if (match_service_match(service_filter, STR(service_name)) == 0)
- continue;
- }
- print_master_line(mode, argv);
- }
- if (service_filter) {
+ for (masterp = master_table; (argv = masterp->argv) != 0; masterp++)
+ if (service_filter == 0
+ || match_service_match(service_filter, masterp->name_space) != 0)
+ print_master_line(mode, argv);
+ if (service_filter != 0)
argv_free(service_filter);
- vstring_free(service_name);
- }
}
/* show_sasl - show SASL plug-in types */
@@ -1801,79 +1847,67 @@ static void show_sasl(int what)
argv_free(sasl_argv);
}
+/* flag_unused_parameters - warn about unused parameters */
+
+static void flag_unused_parameters(DICT *dict, const char *conf_name,
+ PC_MASTER_ENT *local_scope)
+{
+ const char *myname = "flag_unused_parameters";
+ const char *param_name;
+ const char *param_value;
+ int how;
+
+ /*
+ * Iterate over all entries, and flag parameter names that aren't used
+ * anywhere. Show the warning message at the end of the output.
+ */
+ if (dict->sequence == 0)
+ msg_panic("%s: parameter dictionary %s has no iterator",
+ myname, conf_name);
+ for (how = DICT_SEQ_FUN_FIRST;
+ dict->sequence(dict, how, ¶m_name, ¶m_value) == 0;
+ how = DICT_SEQ_FUN_NEXT) {
+ if (htable_locate(param_table, param_name) == 0
+ && (local_scope == 0
+ || htable_locate(local_scope->valid_names, param_name) == 0)) {
+ vstream_fflush(VSTREAM_OUT);
+ msg_warn("%s/%s: unused parameter: %s=%s",
+ var_config_dir, conf_name, param_name, param_value);
+ }
+ }
+}
+
/* flag_unused_main_parameters - warn about unused parameters */
static void flag_unused_main_parameters(void)
{
const char *myname = "flag_unused_main_parameters";
DICT *dict;
- const char *param_name;
- const char *param_value;
- int how;
/*
* Iterate over all main.cf entries, and flag parameter names that aren't
- * used anywhere. Show the warning message at the end of the output.
+ * used anywhere.
*/
if ((dict = dict_handle(CONFIG_DICT)) == 0)
msg_panic("%s: parameter dictionary %s not found",
myname, CONFIG_DICT);
- if (dict->sequence == 0)
- msg_panic("%s: parameter dictionary %s has no iterator",
- myname, CONFIG_DICT);
- for (how = DICT_SEQ_FUN_FIRST;
- dict->sequence(dict, how, ¶m_name, ¶m_value) == 0;
- how = DICT_SEQ_FUN_NEXT) {
- if (htable_locate(param_table, param_name) == 0) {
- vstream_fflush(VSTREAM_OUT);
- msg_warn("%s/" MAIN_CONF_FILE ": unused parameter: %s=%s",
- var_config_dir, param_name, param_value);
- }
- }
+ flag_unused_parameters(dict, MAIN_CONF_FILE, (PC_MASTER_ENT *) 0);
}
/* flag_unused_master_parameters - warn about unused parameters */
static void flag_unused_master_parameters(void)
{
- ARGV **argvp;
- ARGV *argv;
- int field;
- char *arg;
- char *saved_arg;
- char *param_name;
- char *param_value;
+ PC_MASTER_ENT *masterp;
+ DICT *dict;
/*
* Iterate over all master.cf entries, and flag parameter names that
- * aren't used anywhere. Show the warning message at the end of the
- * output.
- *
- * XXX It is possible that a user-defined parameter is defined in master.cf
- * with "-o smtpd_restriction_classes=name", or with "-o name1=value1"
- * and then used in a "-o name2=$name1" macro expansion in that same
- * master.cf entry. To handle this we need to give each master.cf entry
- * its own name space. Until then, we always log "unused parameter"
- * warnings for "-o user-defined-name=value" entries.
+ * aren't used anywhere.
*/
- for (argvp = master_table; (argv = *argvp) != 0; argvp++) {
- for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) {
- arg = argv->argv[field];
- if (arg[0] != '-')
- break;
- if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) {
- saved_arg = mystrdup(arg);
- if (split_nameval(saved_arg, ¶m_name, ¶m_value) == 0
- && htable_locate(param_table, param_name) == 0) {
- vstream_fflush(VSTREAM_OUT);
- msg_warn("%s/" MASTER_CONF_FILE ": unused parameter: %s=%s",
- var_config_dir, param_name, param_value);
- }
- myfree(saved_arg);
- field += 1;
- }
- }
- }
+ for (masterp = master_table; masterp->argv != 0; masterp++)
+ if ((dict = masterp->all_params) != 0)
+ flag_unused_parameters(dict, MASTER_CONF_FILE, masterp);
}
MAIL_VERSION_STAMP_DECLARE;
diff --git a/postfix/src/postconf/test12.ref b/postfix/src/postconf/test12.ref
new file mode 100644
index 000000000..a9f5eb4a2
--- /dev/null
+++ b/postfix/src/postconf/test12.ref
@@ -0,0 +1,2 @@
+foo inet - n n - 0 spawn -o always_bcc=$bar -o
+foo inet - n n - 0 spawn -o always_bcc=$bar -o
diff --git a/postfix/src/postconf/test13.ref b/postfix/src/postconf/test13.ref
new file mode 100644
index 000000000..09787fadb
--- /dev/null
+++ b/postfix/src/postconf/test13.ref
@@ -0,0 +1,3 @@
+bar = yes
+config_directory = .
+./postconf: warning: ./main.cf: unused parameter: baz=xx
diff --git a/postfix/src/postconf/test14.ref b/postfix/src/postconf/test14.ref
new file mode 100644
index 000000000..98884f3f0
--- /dev/null
+++ b/postfix/src/postconf/test14.ref
@@ -0,0 +1,3 @@
+config_directory = .
+smtpd_restriction_classes = bar
+./postconf: warning: ./master.cf: unused parameter: baz=xx
diff --git a/postfix/src/postconf/test15.ref b/postfix/src/postconf/test15.ref
new file mode 100644
index 000000000..2a15ca84d
--- /dev/null
+++ b/postfix/src/postconf/test15.ref
@@ -0,0 +1,3 @@
+baz = yy
+config_directory = .
+./postconf: warning: ./main.cf: unused parameter: bar=xx
diff --git a/postfix/src/postconf/test5.ref b/postfix/src/postconf/test5.ref
index 3c853fff1..41bee93ae 100644
--- a/postfix/src/postconf/test5.ref
+++ b/postfix/src/postconf/test5.ref
@@ -1,2 +1 @@
config_directory = .
-./postconf: warning: ./master.cf: unused parameter: bar=yes