-TPC_DBMS_INFO
-TPC_EVAL_CTX
-TPC_MASTER_ENT
+-TPC_PARAM_CTX
-TPC_PARAM_NODE
-TPC_SERVICE_DEF
-TPC_STRING_NV
20121221
- Feature: "postconf -x" support to expand $nama in parameter
- values. Files: postconf/postconf_main.c, postconf/postconf.h,
- postconf/postconf_node.c, postconf/postconf.c.
+ Feature: "postconf -x" support to expand $name in main.cf
+ parameter values. Files: postconf/postconf_main.c,
+ postconf/postconf.h, postconf/postconf_node.c, postconf/postconf.c.
+
+20121222
+
+ Feature: postconf support to warn about an attempt to modify
+ a read-only parameter (process_name etc.) in main.cf or
+ master.cf. Files: postconf/postconf_readonly.c,
+ postconf/postconf_builtin.c.
+
+20121223
+
+ Feature: postconf support to warn about an undefined $name
+ in a parameter value in main.cf or master.cf (except for
+ backwards-compatibility parameters such as $virtual_maps)
+ Files: postconf/postconf_user.c, postconf_dbms.c,
+ postconf_builtin.c, util/dict_ht.c, util/htable.c.
+
+ Feature: "postconf -Mx" support to expand $name in master.cf
+ parameter values. Files: postconf/postconf_master.c,
+ postconf/postconf_lookup.c, postconf/postconf_main.c,
+ postconf/postconf.c.
+
+20121224
+
+ Feature: "postconf -Mn" support to print only master.cf
+ entries that have "-o name=value" parameter setttings.
+ Files: postconf/postconf_master.c.
If you upgrade from Postfix 2.8 or earlier, read RELEASE_NOTES-2.9
before proceeding.
+Incompatible changes with snapshot 20121224
+===========================================
+
+The postconf command produces more warnings:
+
+- An attempt to modify a read-only parameter (process_name, process_id)
+ in main.cf or master.cf.
+
+- An undefined $name in a parameter value in main.cf or master.cf
+ (except for backwards-compatibility parameters such as $virtual_maps).
+
+Major changes with snapshot 20121224
+====================================
+
+The postconf command has been updated to make trouble-shooting (and
+support) easier. In summary, use "postconf -Mnxf" and "postconf
+-nxf" to review master.cf and main.cf parameter settings with
+expanded parameter values.
+
+- "postconf -x" now expands $name in main.cf and master.cf parameter
+ values.
+
+- "postconf -Mn" now shows only master.cf entries with "-o name=value"
+ parameter settings.
+
+- postconf warns about attempts to modify a read-only parameter
+ (process_name, process_id) in main.cf or master.cf.
+
+- postconf warns about an undefined $name in a parameter value in
+ main.cf or master.cf (except for backwards-compatibility parameters
+ such as $virtual_maps).
+
Incompatible changes with snapshot 20121123
===========================================
There is no need to change the value of smtpd_recipient_restrictions.
-
Major changes with snapshot 20121007
====================================
<b>Managing <a href="master.5.html">master.cf</a>:</b>
- <b>postconf</b> [<b>-fMv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service ...</i>]
+ <b>postconf</b> [<b>-fMnvx</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service ...</i>]
<b>Managing bounce message templates:</b>
This feature is available with Postfix 2.9 and
later.
- <b>-n</b> Print <a href="postconf.5.html"><b>main.cf</b></a> parameter settings that are explic-
- itly specified in <a href="postconf.5.html"><b>main.cf</b></a>. Specify <b>-nf</b> to fold
- long lines for human readability (Postfix 2.9 and
- later).
+ <b>-n</b> Print only <i>name</i>=<i>value</i> parameter settings that are
+ explicitly specified in <a href="postconf.5.html"><b>main.cf</b></a>. When specified
+ with <b>-M</b>, print only <a href="master.5.html"><b>master.cf</b></a> entries that have "-o
+ <i>name</i>=<i>value</i>" parameter settings (Postfix 2.10 and
+ later). Specify <b>-nf</b> to fold long lines for human
+ readability (Postfix 2.9 and later).
<b>-t</b> [<i>template</i><b>_</b><i>file</i>]
Display the templates for text that appears at the
tiple <b>-v</b> options make the software increasingly
verbose.
- <b>-x</b> Expand <i>$name</i> in parameter values. The expansion is
- recursive.
+ <b>-x</b> Expand <i>$name</i> in <a href="postconf.5.html"><b>main.cf</b></a> or <a href="master.5.html"><b>master.cf</b></a> parameter val-
+ ues. The expansion is recursive.
+
+ This feature is available with Postfix 2.10 and
+ later.
<b>-X</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and remove the
- parameters named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
+ parameters named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
The file is copied to a temporary file then renamed
into place. Specify a list of parameter names, not
- "<i>name</i>=<i>value</i>" pairs. There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
+ "<i>name</i>=<i>value</i>" pairs. There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
mand to perform the reverse operation.
- This feature is available with Postfix 2.10 and
+ This feature is available with Postfix 2.10 and
later.
- <b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and comment
+ <b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and comment
out the parameters named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command
- line, so that those parameters revert to their
- default values. The file is copied to a temporary
- file then renamed into place. Specify a list of
- parameter names, not "<i>name</i>=<i>value</i>" pairs. There is
+ line, so that those parameters revert to their
+ default values. The file is copied to a temporary
+ file then renamed into place. Specify a list of
+ parameter names, not "<i>name</i>=<i>value</i>" pairs. There is
no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse oper-
ation.
- This feature is available with Postfix 2.6 and
+ This feature is available with Postfix 2.6 and
later.
<b>DIAGNOSTICS</b>
Directory with Postfix configuration files.
<b>CONFIGURATION PARAMETERS</b>
- The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> 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
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a> (empty)</b>
- Pathname of a configuration file with bounce mes-
+ Pathname of a configuration file with bounce mes-
sage templates.
<b>FILES</b>
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
\fBManaging master.cf:\fR
-\fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR]
+\fBpostconf\fR [\fB-fMnvx\fR] [\fB-c \fIconfig_dir\fR]
[\fIservice ...\fR]
\fBManaging bounce message templates:\fR
This feature is available with Postfix 2.9 and later.
.IP \fB-n\fR
-Print \fBmain.cf\fR parameter settings that are explicitly
-specified in \fBmain.cf\fR.
+Print only \fIname\fR=\fIvalue\fR parameter settings that
+are explicitly specified in \fBmain.cf\fR. When specified
+with \fB-M\fR, print only \fBmaster.cf\fR entries that have
+"-o \fIname\fR=\fIvalue\fR" parameter settings (Postfix
+2.10 and later).
Specify \fB-nf\fR to fold long lines for human readability
(Postfix 2.9 and later).
.IP "\fB-t\fR [\fItemplate_file\fR]"
Enable verbose logging for debugging purposes. Multiple \fB-v\fR
options make the software increasingly verbose.
.IP \fB-x\fR
-Expand \fI$name\fR in parameter values. The expansion is
-recursive.
+Expand \fI$name\fR in \fBmain.cf\fR or \fBmaster.cf\fR
+parameter values. The expansion is recursive.
+
+This feature is available with Postfix 2.10 and later.
.IP \fB-X\fR
Edit the \fBmain.cf\fR configuration file, and remove
the parameters named on the \fBpostconf\fR(1) command line.
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20121221"
+#define MAIL_RELEASE_DATE "20121224"
#define MAIL_VERSION_NUMBER "2.10"
#ifdef SNAPSHOT
SHELL = /bin/sh
SRCS = postconf.c postconf_builtin.c postconf_edit.c postconf_main.c \
postconf_master.c postconf_misc.c postconf_node.c postconf_other.c \
- postconf_service.c postconf_unused.c postconf_user.c postconf_dbms.c
+ postconf_service.c postconf_unused.c postconf_user.c postconf_dbms.c \
+ postconf_lookup.c
OBJS = postconf.o postconf_builtin.o postconf_edit.o postconf_main.o \
postconf_master.o postconf_misc.o postconf_node.o postconf_other.o \
- postconf_service.o postconf_unused.o postconf_user.o postconf_dbms.o
+ postconf_service.o postconf_unused.o postconf_user.o postconf_dbms.o \
+ postconf_lookup.o
HDRS = postconf.h
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
MAKES = bool_table.h bool_vars.h int_table.h int_vars.h str_table.h \
str_vars.h time_table.h time_vars.h raw_table.h raw_vars.h \
nint_table.h nint_vars.h nbool_table.h nbool_vars.h long_table.h \
- long_vars.h
+ long_vars.h str_fn_table.h str_fn_vars.h
TEST_TMP= main.cf master.cf test*.tmp
DUMMIES = makes_dummy # for "make -j"
PROG = postconf
(echo "# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE"; \
echo "# TEXT HERE JUST SHOWS DEFAULT SETTINGS BUILT INTO POSTFIX."; \
echo "#"; ./$(PROG) -d -c ../../conf) | \
- egrep -v '^(myhostname|mydomain|mynetworks) ' >$@
+ egrep -v '^(myhostname|mydomain|mynetworks|process_name|process_id) ' >$@
$(OBJS): ../../conf/makedefs.out
tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \
test12 test13 test14 test15 test16 test17 test18 test19 test20 test21 \
test22 test23 test24 test25 test26 test27 test28 test29 test30 test4b \
- test31 test32 test33
+ test31 test32 test33 test34 test35 test36 test37 test38 test39
root_tests:
test28: $(PROG) test28.ref
rm -f main.cf master.cf
touch main.cf master.cf
- echo 'xx = proxy:ldap:foo' >> main.cf
+ echo 'xx = ldap:foo' >> main.cf
echo 'foo_domain = bar' >> main.cf
echo 'header_checks = ldap:hh' >> main.cf
echo 'hh_domain = whatever' >> main.cf
test29: $(PROG) test29.ref
rm -f main.cf master.cf
touch main.cf master.cf
- echo 'ldapxx = proxy:ldap:ldapfoo' >> main.cf
+ echo 'ldapxx = ldap:ldapfoo' >> main.cf
echo 'ldapfoo_domain = bar' >> main.cf
echo 'ldapfoo_domainx = bar' >> main.cf
- echo 'mysqlxx = proxy:mysql:mysqlfoo' >> main.cf
+ echo 'mysqlxx = mysql:mysqlfoo' >> main.cf
echo 'mysqlfoo_domain = bar' >> main.cf
echo 'mysqlfoo_domainx = bar' >> main.cf
- echo 'pgsqlxx = proxy:pgsql:pgsqlfoo' >> main.cf
+ echo 'pgsqlxx = pgsql:pgsqlfoo' >> main.cf
echo 'pgsqlfoo_domain = bar' >> main.cf
echo 'pgsqlfoo_domainx = bar' >> main.cf
- echo 'sqlitexx = proxy:sqlite:sqlitefoo' >> main.cf
+ echo 'sqlitexx = sqlite:sqlitefoo' >> main.cf
echo 'sqlitefoo_domain = bar' >> main.cf
echo 'sqlitefoo_domainx = bar' >> main.cf
- echo 'memcachexx = proxy:memcache:memcachefoo' >> main.cf
+ echo 'memcachexx = memcache:memcachefoo' >> main.cf
echo 'memcachefoo_domain = bar' >> main.cf
echo 'memcachefoo_domainx = bar' >> main.cf
./$(PROG) -nc . >test29.tmp 2>&1
diff test33.ref test33.tmp
rm -f main.cf master.cf test33.tmp
+test34: $(PROG) test34.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo 'mydestination=whatever' >> main.cf
+ echo 'process_name=xxx' >> main.cf
+ echo 'process_id=yyy' >> main.cf
+ ./$(PROG) -xc . mydestination process_name >test34.tmp 2>&1
+ diff test34.ref test34.tmp
+ rm -f main.cf master.cf test34.tmp
+
+test35: $(PROG) test35.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo whatevershebrings unix - n n - 0 other >> master.cf
+ echo ' -o body_checks=whatever' >> master.cf
+ echo ' -o process_name=aaa' >> master.cf
+ echo ' -o process_id=bbb' >> master.cf
+ ./$(PROG) -xc . process_name >test35.tmp 2>&1
+ diff test35.ref test35.tmp
+ rm -f main.cf master.cf test35.tmp
+
+test36: $(PROG) test36.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo 'mydestination=$$virtual_mapx' >> main.cf
+ echo 'virtual_alias_maps=$$virtual_maps' >> main.cf
+ ./$(PROG) -nxc . >test36.tmp 2>&1
+ diff test36.ref test36.tmp
+ rm -f main.cf master.cf test36.tmp
+
+test37: $(PROG) test37.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo 'xxx=yyy' >> main.cf
+ echo 'aaa=bbb' >> main.cf
+ echo whatever unix - n n - 0 other >> master.cf
+ echo ' -o mydestination=$$xxx' >> master.cf
+ echo ' -o always_bcc=$$aaa' >> master.cf
+ echo ' -o aaa=ccc' >> master.cf
+ ./$(PROG) -Mfxc . >test37.tmp 2>&1
+ diff test37.ref test37.tmp
+ rm -f main.cf master.cf test37.tmp
+
+test38: $(PROG) test38.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar unix - n n - 0 other >> master.cf
+ echo ' -o aaa=ccc' >> master.cf
+ ./$(PROG) -Mnfxc . >test38.tmp 2>&1
+ diff test38.ref test38.tmp
+ rm -f main.cf master.cf test38.tmp
+
+test39: $(PROG) test39.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mfc . unix >test39.tmp 2>&1
+ diff test39.ref test39.tmp
+ rm -f main.cf master.cf test39.tmp
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
postconf_builtin.o: postconf_builtin.c
postconf_builtin.o: raw_table.h
postconf_builtin.o: raw_vars.h
+postconf_builtin.o: str_fn_table.h
+postconf_builtin.o: str_fn_vars.h
postconf_builtin.o: str_table.h
postconf_builtin.o: str_vars.h
postconf_builtin.o: time_table.h
postconf_edit.o: ../../include/vstring_vstream.h
postconf_edit.o: postconf.h
postconf_edit.o: postconf_edit.c
+postconf_lookup.o: ../../include/argv.h
+postconf_lookup.o: ../../include/dict.h
+postconf_lookup.o: ../../include/htable.h
+postconf_lookup.o: ../../include/mac_expand.h
+postconf_lookup.o: ../../include/mac_parse.h
+postconf_lookup.o: ../../include/mail_conf.h
+postconf_lookup.o: ../../include/msg.h
+postconf_lookup.o: ../../include/myflock.h
+postconf_lookup.o: ../../include/mymalloc.h
+postconf_lookup.o: ../../include/stringops.h
+postconf_lookup.o: ../../include/sys_defs.h
+postconf_lookup.o: ../../include/vbuf.h
+postconf_lookup.o: ../../include/vstream.h
+postconf_lookup.o: ../../include/vstring.h
+postconf_lookup.o: postconf.h
+postconf_lookup.o: postconf_lookup.c
postconf_main.o: ../../include/argv.h
postconf_main.o: ../../include/dict.h
postconf_main.o: ../../include/htable.h
}
}
}
+/^(static| )*(const +)?CONFIG_STR_FN_TABLE .*\{/,/\};/ {
+ if ($1 ~ /^VAR/) {
+ str_fn_vars["char *" substr($3,2,length($3)-2) ";"] = 1
+ $2 = "pc_" $2
+ if (++stab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
+ str_fn_table[$0] = 1
+ }
+ }
+}
/^(static| )*(const +)?CONFIG_RAW_TABLE .*\{/,/\};/ {
if ($1 ~ /^VAR/) {
raw_vars["char *" substr($3,2,length($3)-2) ";"] = 1
print key
print "EOF"
+ print "cat >str_fn_vars.h <<'EOF'"
+ for (key in str_fn_vars)
+ print key
+ print "EOF"
+
print "cat >raw_vars.h <<'EOF'"
for (key in raw_vars)
print key
print key
print "EOF"
+ print "sed 's/[ ][ ]*/ /g' >str_fn_table.h <<'EOF'"
+ for (key in str_fn_table)
+ print key
+ print "EOF"
+
print "sed 's/[ ][ ]*/ /g' >raw_table.h <<'EOF'"
for (key in raw_table)
print key
/*
/* \fBManaging master.cf:\fR
/*
-/* \fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR]
+/* \fBpostconf\fR [\fB-fMnvx\fR] [\fB-c \fIconfig_dir\fR]
/* [\fIservice ...\fR]
/*
/* \fBManaging bounce message templates:\fR
/*
/* This feature is available with Postfix 2.9 and later.
/* .IP \fB-n\fR
-/* Print \fBmain.cf\fR parameter settings that are explicitly
-/* specified in \fBmain.cf\fR.
+/* Print only \fIname\fR=\fIvalue\fR parameter settings that
+/* are explicitly specified in \fBmain.cf\fR. When specified
+/* with \fB-M\fR, print only \fBmaster.cf\fR entries that have
+/* "-o \fIname\fR=\fIvalue\fR" parameter settings (Postfix
+/* 2.10 and later).
/* Specify \fB-nf\fR to fold long lines for human readability
/* (Postfix 2.9 and later).
/* .IP "\fB-t\fR [\fItemplate_file\fR]"
/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
/* options make the software increasingly verbose.
/* .IP \fB-x\fR
-/* Expand \fI$name\fR in parameter values. The expansion is
-/* recursive.
+/* Expand \fI$name\fR in \fBmain.cf\fR or \fBmaster.cf\fR
+/* parameter values. The expansion is recursive.
+/*
+/* This feature is available with Postfix 2.10 and later.
/* .IP \fB-X\fR
/* Edit the \fBmain.cf\fR configuration file, and remove
/* the parameters named on the \fBpostconf\fR(1) command line.
/*
* Sanity check.
*/
- junk = (cmd_mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT | COMMENT_OUT | SHOW_MASTER | EDIT_EXCL));
- if (junk != 0 && ((junk != SHOW_DEFS && junk != SHOW_NONDEF
+ junk = (cmd_mode & (SHOW_DEFS | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT | COMMENT_OUT | SHOW_MASTER | EDIT_EXCL));
+ if (junk != 0 && ((junk != SHOW_DEFS
&& junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN
&& junk != SHOW_SASL_SERV && junk != SHOW_SASL_CLNT
&& junk != COMMENT_OUT && junk != SHOW_MASTER
&& junk != EDIT_EXCL)
|| ext_argv != 0))
- msg_fatal("specify one of -a, -A, -b, -d, -e, -#, -l, -m, -M, -n, and -X");
- if ((cmd_mode & SHOW_EVAL) != 0 && junk != 0 && junk != SHOW_DEFS && junk != SHOW_NONDEF)
- msg_fatal("do not specify -x with -a, -A, -b, -e, -#, -l, -m, -M, or -X");
+ msg_fatal("specify one of -a, -A, -b, -d, -e, -#, -l, -m, -M, and -X");
+ if ((cmd_mode & SHOW_EVAL) != 0 && junk != 0 && junk != SHOW_DEFS && junk != SHOW_MASTER)
+ msg_fatal("do not specify -x with -a, -A, -b, -e, -#, -l, -m, or -X");
+ if ((cmd_mode & SHOW_NONDEF) != 0 && junk != 0 && junk != SHOW_MASTER)
+ msg_fatal("do not specify -n with -a, -A, -b, -d, -e, -#, -l, -m, or -X");
/*
* Display bounce template information and exit.
*/
else if (cmd_mode & SHOW_MASTER) {
read_master(FAIL_ON_OPEN_ERROR);
+ read_parameters();
+ register_builtin_parameters(basename(argv[0]), getpid());
+ register_service_parameters();
+ register_user_parameters();
show_master(cmd_mode, argv + optind);
}
if ((cmd_mode & SHOW_DEFS) == 0) {
read_parameters();
}
- register_builtin_parameters();
+ register_builtin_parameters(basename(argv[0]), getpid());
/*
* Add service-dependent parameters (service names from master.cf)
/* DESCRIPTION
/* .nf
+ /*
+ * System library.
+ */
+#include <unistd.h>
+
/*
* Utility library.
*/
int flags; /* see below */
char *param_data; /* mostly, the default value */
const char *(*convert_fn) (char *); /* value to string */
- const char *cached_defval; /* cached default value */
} PC_PARAM_NODE;
/* Values for flags. See the postconf_node module for narrative text. */
#define PC_PARAM_FLAG_BUILTIN (1<<1) /* built-in parameter name */
#define PC_PARAM_FLAG_SERVICE (1<<2) /* service-defined parameter name */
#define PC_PARAM_FLAG_USER (1<<3) /* user-defined parameter name */
+#define PC_PARAM_FLAG_LEGACY (1<<4) /* legacy parameter name */
+#define PC_PARAM_FLAG_READONLY (1<<5) /* legacy parameter name */
+#define PC_PARAM_FLAG_DBMS (1<<6) /* dbms-defined parameter name */
#define PC_PARAM_MASK_CLASS \
(PC_PARAM_FLAG_BUILTIN | PC_PARAM_FLAG_SERVICE | PC_PARAM_FLAG_USER)
((node)->flags = (((node)->flags & ~PC_PARAM_MASK_CLASS) | (class)))
#define PC_RAW_PARAMETER(node) ((node)->flags & PC_PARAM_FLAG_RAW)
+#define PC_LEGACY_PARAMETER(node) ((node)->flags & PC_PARAM_FLAG_LEGACY)
+#define PC_READONLY_PARAMETER(node) ((node)->flags & PC_PARAM_FLAG_READONLY)
+#define PC_DBMS_PARAMETER(node) ((node)->flags & PC_PARAM_FLAG_DBMS)
/* Values for param_data. See postconf_node module for narrative text. */
#define PC_PARAM_NO_DATA ((char *) 0)
/*
* postconf_builtin.c.
*/
-extern void register_builtin_parameters(void);
+extern void register_builtin_parameters(const char *, pid_t);
/*
* postconf_service.c.
*/
extern void register_service_parameters(void);
+ /*
+ * Parameter context structure.
+ */
+typedef struct {
+ PC_MASTER_ENT *local_scope;
+ int param_class;
+} PC_PARAM_CTX;
+
/*
* postconf_user.c.
*/
const char *(*) (const char *, int, char *),
PC_MASTER_ENT *);
+ /*
+ * postconf_lookup.c.
+ */
+const char *lookup_parameter_value(int, const char *, PC_MASTER_ENT *,
+ PC_PARAM_NODE *);
+const char *expand_parameter_value(int, const char *, PC_MASTER_ENT *);
+
/*
* postconf_unused.c.
*/
/* SYNOPSIS
/* #include <postconf.h>
/*
-/* void register_builtin_parameters()
+/* void register_builtin_parameters(procname, pid)
+/* const char *procname;
+/* pid_t pid;
/* DESCRIPTION
/* register_builtin_parameters() initializes the global parameter
/* name space and adds all built-in parameter information.
+/*
+/* Arguments:
+/*.IP procname
+/* Provides the default value for the "process_name" parameter.
+/*.IP pid
+/* Provides the default value for the "process_id" parameter.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* LICENSE
};
/*
- * Parameters with default values obtained via function calls.
+ * Legacy parameters for backwards compatibility.
*/
-char *var_myhostname;
-char *var_mydomain;
-char *var_mynetworks;
+static const CONFIG_STR_TABLE legacy_str_table[] = {
+ {"virtual_maps", ""},
+ {"fallback_relay", ""},
+ {"authorized_verp_clients", ""},
+ {"smtpd_client_connection_limit_exceptions", ""},
+ 0,
+};
-static const char *check_myhostname(void);
-static const char *check_mydomainname(void);
-static const char *check_mynetworks(void);
+ /*
+ * Parameters whose default values are normally initialized by calling a
+ * function. We direct the calls to our own versions of those functions
+ * because the run-time conditions are slightly different.
+ *
+ * Important: if the evaluation of these parameters has any side effects, then
+ * those side effects must happen only once.
+ */
+static const char *pc_check_myhostname(void);
+static const char *pc_check_mydomainname(void);
+static const char *pc_mynetworks(void);
+
+#include "str_fn_vars.h"
static const CONFIG_STR_FN_TABLE str_fn_table[] = {
- VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0,
- VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0,
- 0,
-};
-static const CONFIG_STR_FN_TABLE str_fn_table_2[] = {
- VAR_MYNETWORKS, check_mynetworks, &var_mynetworks, 1, 0,
+#include "str_fn_table.h"
0,
};
+ /*
+ * Parameters whose default values are normally initialized by ad-hoc code.
+ * The AWK script cannot identify these parameters or values, so we provide
+ * our own.
+ *
+ * Important: if the evaluation of these parameters has any side effects, then
+ * those side effects must happen only once.
+ */
+static CONFIG_STR_TABLE adhoc_procname = {VAR_PROCNAME};
+static CONFIG_INT_TABLE adhoc_pid = {VAR_PID};
+
#define STR(x) vstring_str(x)
-/* check_myhostname - lookup hostname and validate */
+/* pc_check_myhostname - lookup hostname and validate */
-static const char *check_myhostname(void)
+static const char *pc_check_myhostname(void)
{
static const char *name;
const char *dot;
const char *name;
if ((name = mail_conf_lookup_eval(VAR_MYHOSTNAME)) == 0)
- name = check_myhostname();
- var_myhostname = mystrdup(name);
+ name = pc_check_myhostname();
+ var_mynetworks = mystrdup(name);
}
-/* check_mydomainname - lookup domain name and validate */
+/* pc_check_mydomainname - lookup domain name and validate */
-static const char *check_mydomainname(void)
+static const char *pc_check_mydomainname(void)
{
+ static const char *domain;
char *dot;
+ /*
+ * Use cached result.
+ */
+ if (domain)
+ return (domain);
+
/*
* Use the hostname when it is not a FQDN ("foo"), or when the hostname
* actually is a domain name ("foo.com").
*/
- if (var_myhostname == 0)
+ if (var_mynetworks == 0)
get_myhostname();
- if ((dot = strchr(var_myhostname, '.')) == 0 || strchr(dot + 1, '.') == 0)
- return (DEF_MYDOMAIN);
- return (dot + 1);
+ if ((dot = strchr(var_mynetworks, '.')) == 0 || strchr(dot + 1, '.') == 0)
+ return (domain = DEF_MYDOMAIN);
+ return (domain = mystrdup(dot + 1));
}
-/* check_mynetworks - lookup network address list */
+/* pc_mynetworks - lookup network address list */
-static const char *check_mynetworks(void)
+static const char *pc_mynetworks(void)
{
+ static const char *networks;
INET_PROTO_INFO *proto_info;
const char *junk;
+ /*
+ * Use cached result.
+ */
+ if (networks)
+ return (networks);
+
if (var_inet_interfaces == 0) {
if ((cmd_mode & SHOW_DEFS)
|| (junk = mail_conf_lookup_eval(VAR_INET_INTERFACES)) == 0)
var_inet_protocols = mystrdup(junk);
proto_info = inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols);
}
- return (mynetworks());
+ return (networks = mystrdup(mynetworks()));
}
/* convert_bool_parameter - get boolean parameter string value */
/* register_builtin_parameters - add built-ins to the global name space */
-void register_builtin_parameters(void)
+void register_builtin_parameters(const char *procname, pid_t pid)
{
const char *myname = "register_builtin_parameters";
const CONFIG_TIME_TABLE *ctt;
for (cft = str_fn_table; cft->name; cft++)
PC_PARAM_TABLE_ENTER(param_table, cft->name, PC_PARAM_FLAG_BUILTIN,
(char *) cft, convert_str_fn_parameter);
- for (cft = str_fn_table_2; cft->name; cft++)
- PC_PARAM_TABLE_ENTER(param_table, cft->name, PC_PARAM_FLAG_BUILTIN,
- (char *) cft, convert_str_fn_parameter);
for (rst = raw_table; rst->name; rst++)
PC_PARAM_TABLE_ENTER(param_table, rst->name,
PC_PARAM_FLAG_BUILTIN | PC_PARAM_FLAG_RAW,
for (lst = long_table; lst->name; lst++)
PC_PARAM_TABLE_ENTER(param_table, lst->name, PC_PARAM_FLAG_BUILTIN,
(char *) lst, convert_long_parameter);
+
+ /*
+ * Register legacy parameters (used as a backwards-compatible migration
+ * aid).
+ */
+ for (cst = legacy_str_table; cst->name; cst++)
+ PC_PARAM_TABLE_ENTER(param_table, cst->name, PC_PARAM_FLAG_LEGACY,
+ (char *) cst, convert_str_parameter);
+
+ /*
+ * Register parameters whose default value is normally initialized by
+ * ad-hoc code.
+ */
+ adhoc_procname.defval = mystrdup(procname);
+ PC_PARAM_TABLE_ENTER(param_table, adhoc_procname.name,
+ PC_PARAM_FLAG_BUILTIN | PC_PARAM_FLAG_READONLY,
+ (char *) &adhoc_procname, convert_str_parameter);
+ adhoc_pid.defval = pid;
+ PC_PARAM_TABLE_ENTER(param_table, adhoc_pid.name,
+ PC_PARAM_FLAG_BUILTIN | PC_PARAM_FLAG_READONLY,
+ (char *) &adhoc_pid, convert_int_parameter);
}
/* names for that database type.
/* .IP flag_parameter
/* A function that takes as arguments a candidate parameter
-/* name, an unused value, and a local namespace pointer. The
+/* name, an unused value, and a PC_PARAM_CTX pointer. The
/* function will flag the parameter as "used" if it has a
/* "name=value" entry in the local or global namespace.
/* .IP local_scope
0,
};
-/* register_dbms_parameters_cb - mac_expand() call-back */
-
-static const char *register_dbms_parameters_cb(const char *mac_name,
- int unused_mode,
- char *context)
-{
- PC_MASTER_ENT *local_scope = (PC_MASTER_ENT *) context;
- const char *mac_val;
-
- /*
- * Local namespace "name=value" settings are always explicit. They have
- * precedence over global namespace "name=value" settings which are
- * either explicit or defined by their default value.
- */
- if (local_scope == 0
- || (mac_val = dict_get(local_scope->all_params, mac_name)) == 0)
- mac_val = mail_conf_lookup(mac_name);
- return (mac_val);
-}
-
/* register_dbms_parameters - look for database_type:prefix_name */
void register_dbms_parameters(const char *param_value,
static VSTRING *buffer = 0;
static VSTRING *candidate = 0;
const char **cpp;
+ PC_PARAM_CTX param_ctx;
+
+ param_ctx.local_scope = local_scope;
+ param_ctx.param_class = PC_PARAM_FLAG_DBMS | PC_PARAM_FLAG_USER;
/*
- * Emulate Postfix parameter value expansion, prepending the appropriate
- * local (master.cf "-o name-value") namespace to the global (main.cf
- * "name=value") namespace.
- *
- * XXX This does not examine both sides of conditional macro expansion, and
- * may expand the "wrong" conditional macros. This is the best we can do
- * for legacy database configuration support.
+ * XXX This does not examine both sides of conditional macro expansion,
+ * and may expand the "wrong" conditional macros. This is the best we can
+ * do for legacy database configuration support.
*/
-#define NO_SCAN_FILTER ((char *) 0)
-
- (void) mac_expand(buffer ? buffer : (buffer = vstring_alloc(100)),
- param_value, MAC_EXP_FLAG_RECURSE, NO_SCAN_FILTER,
- register_dbms_parameters_cb, (char *) local_scope);
+ bufp = STR(vstring_strcpy(buffer ? buffer : (buffer = vstring_alloc(100)),
+ expand_parameter_value(SHOW_EVAL, param_value, local_scope)));
/*
* Naive parsing. We don't really know if the parameter specifies free
* text or a list of databases.
*/
- bufp = STR(buffer);
while ((db_type = mystrtok(&bufp, " ,\t\r\n")) != 0) {
/*
- * Skip over "proxy:" indirections.
- */
- while ((prefix = split_at(db_type, ':')) != 0
- && strcmp(db_type, DICT_TYPE_PROXY) == 0)
- db_type = prefix;
-
- /*
- * Look for database:prefix where the prefix is not a pathname and
- * the database is a known type. Synthesize candidate parameter names
+ * Don't skip over "proxy:" indirections. They don't introduce
+ * database-specific main.cf parameters on the proxy client side.
+ *
+ * Look for database:prefix where the prefix is not a pathname and the
+ * database is a known type. Synthesize candidate parameter names
* from the user-defined prefix and from the database-defined suffix
* list, and see if those parameters have a "name=value" entry in the
* local or global namespace.
*/
- if (prefix != 0 && *prefix != '/' && *prefix != '.') {
+ if ((prefix = split_at(db_type, ':')) != 0
+ && *prefix != '/' && *prefix != '.') {
for (dp = dbms_info; dp->db_type != 0; dp++) {
if (strcmp(db_type, dp->db_type) == 0) {
for (cpp = dp->db_suffixes; *cpp; cpp++) {
vstring_sprintf(candidate ? candidate :
(candidate = vstring_alloc(30)),
"%s_%s", prefix, *cpp);
- flag_parameter(STR(candidate), 0, (char *) local_scope);
+ flag_parameter(STR(candidate), 0, (char *) ¶m_ctx);
}
break;
}
--- /dev/null
+/*++
+/* NAME
+/* postconf_lookup 3
+/* SUMMARY
+/* parameter lookup routines
+/* SYNOPSIS
+/* #include <postconf.h>
+/*
+/* const char *lookup_parameter_value(mode, name, local_scope, node)
+/* int mode;
+/* const char *name;
+/* PC_MASTER_ENT *local_scope;
+/* PC_PARAM_NODE *node;
+/*
+/* const char *expand_parameter_value(mode, value, local_scope)
+/* int mode;
+/* const char *value;
+/* PC_MASTER_ENT *local_scope;
+/* DESCRIPTION
+/* These functions perform parameter value lookups. The order
+/* of decreasing precedence is:
+/* .IP \(bu
+/* Search name=value parameter settings in master.cf.
+/* These lookups are disabled with the SHOW_DEFS flag.
+/* .IP \(bu
+/* Search name=value parameter settings in main.cf.
+/* These lookups are disabled with the SHOW_DEFS flag.
+/* .IP \(bu
+/* Search built-in default parameter settings. These lookups
+/* are disabled with the SHOW_NONDEF flag.
+/* .PP
+/* lookup_parameter_value() looks up the value for the named
+/* parameter, and returns null if the name was not found.
+/*
+/* expand_parameter_value() expands $name in the specified
+/* parameter value. This function ignores the SHOW_NONDEF flag.
+/* The result is in static memory that is overwritten with
+/* each call.
+/*
+/* Arguments:
+/* .IP mode
+/* Bit-wise OR of zero or one of the following (other flags
+/* are ignored):
+/* .RS
+/* .IP SHOW_DEFS
+/* Search built-in default parameter settings only.
+/* .IP SHOW_NONDEF
+/* Search local (master.cf) or global (main.cf) name=value
+/* parameter settings only.
+/* .RE
+/* .IP name
+/* The name of a parameter to be looked up.
+/* .IP value
+/* The parameter value where $name should be expanded.
+/* .IP local_scope
+/* Null pointer, or pointer to master.cf entry with local
+/* parameter definitions.
+/* .IP node
+/* Null pointer, or global default settings for the named
+/* parameter.
+/* DIAGNOSTICS
+/* Problems are reported to the standard error stream.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <dict.h>
+#include <stringops.h>
+#include <mac_expand.h>
+
+/* Global library. */
+
+#include <mail_conf.h>
+
+/* Application-specific. */
+
+#include <postconf.h>
+
+#define STR(x) vstring_str(x)
+
+/* lookup_parameter_value - look up specific parameter value */
+
+const char *lookup_parameter_value(int mode, const char *name,
+ PC_MASTER_ENT *local_scope,
+ PC_PARAM_NODE *node)
+{
+ const char *value = 0;
+
+ /*
+ * Use the actual or built-in default parameter value. Local name=value
+ * entries in master.cf take precedence over global name=value entries in
+ * main.cf. Built-in defaults have the lowest precedence.
+ */
+ if ((mode & SHOW_DEFS) != 0
+ || ((local_scope == 0 || local_scope->all_params == 0
+ || (value = dict_get(local_scope->all_params, name)) == 0)
+ && (value = dict_lookup(CONFIG_DICT, name)) == 0
+ && (mode & SHOW_NONDEF) == 0)) {
+ if (node != 0 || (node = PC_PARAM_TABLE_FIND(param_table, name)) != 0)
+ value = convert_param_node(SHOW_DEFS, name, node);
+ }
+ return (value);
+}
+
+ /*
+ * Data structure to pass private state while recursively expanding $name in
+ * parameter values.
+ */
+typedef struct {
+ int mode;
+ PC_MASTER_ENT *local_scope;
+} PC_EVAL_CTX;
+
+/* expand_parameter_value_helper - macro parser call-back routine */
+
+static const char *expand_parameter_value_helper(const char *key,
+ int unused_type,
+ char *context)
+{
+ PC_EVAL_CTX *cp = (PC_EVAL_CTX *) context;
+
+ return (lookup_parameter_value(cp->mode, key, cp->local_scope,
+ (PC_PARAM_NODE *) 0));
+}
+
+/* expand_parameter_value - expand $name in parameter value */
+
+const char *expand_parameter_value(int mode, const char *value,
+ PC_MASTER_ENT *local_scope)
+{
+ const char *myname = "expand_parameter_value";
+ static VSTRING *buf;
+ int status;
+ PC_EVAL_CTX eval_ctx;
+
+ /*
+ * Initialize.
+ */
+ if (buf == 0)
+ buf = vstring_alloc(10);
+
+ /*
+ * Expand macros recursively.
+ *
+ * When expanding $name in "postconf -n" parameter values, don't limit the
+ * search to only non-default parameter values.
+ *
+ * When expanding $name in "postconf -d" parameter values, do limit the
+ * search to only default parameter values.
+ */
+#define DONT_FILTER (char *) 0
+
+ eval_ctx.mode = (mode & ~SHOW_NONDEF);
+ eval_ctx.local_scope = local_scope;
+ status = mac_expand(buf, value, MAC_EXP_FLAG_RECURSE, DONT_FILTER,
+ expand_parameter_value_helper, (char *) &eval_ctx);
+ if (status & MAC_PARSE_ERROR)
+ msg_fatal("macro processing error");
+ if (msg_verbose > 1) {
+ if (strcmp(value, STR(buf)) != 0)
+ msg_info("%s: expand %s -> %s", myname, value, STR(buf));
+ else
+ msg_info("%s: const %s", myname, value);
+ }
+ return (STR(buf));
+}
vstream_fputs("\n", VSTREAM_OUT);
}
-/* lookup_parameter_value - look up specific parameter value */
-
-static const char *lookup_parameter_value(int mode, const char *name,
- PC_PARAM_NODE *node)
-{
- const char *value;
-
- /*
- * Use the actual or built-in default parameter value. Some default
- * values are computed by functions that have side effects, and those
- * functions should be invoked only once. Therefore, when expanding $name
- * in parameter values, we cache the default values.
- */
- if ((mode & SHOW_DEFS) != 0
- || ((value = dict_lookup(CONFIG_DICT, name)) == 0
- && (mode & SHOW_NONDEF) == 0)) {
- if ((value = node->cached_defval) == 0
- && (value = convert_param_node(SHOW_DEFS, name, node)) != 0
- && (mode & SHOW_EVAL) != 0)
- node->cached_defval = value = mystrdup(value);
- }
- return (value);
-}
-
- /*
- * Data structure to pass private state while recursively expanding $name in
- * parameter values.
- */
-typedef struct {
- int mode;
-} PC_EVAL_CTX;
-
-/* expand_parameter_value_helper - macro parser call-back routine */
-
-static const char *expand_parameter_value_helper(const char *key,
- int unused_type,
- char *context)
-{
- PC_PARAM_NODE *node;
- PC_EVAL_CTX *cp = (PC_EVAL_CTX *) context;
-
- /*
- * XXX Do not spam the user with warnings about legacy parameter names in
- * backwards-compatible default settings.
- */
- if ((node = PC_PARAM_TABLE_FIND(param_table, key)) != 0) {
- return (lookup_parameter_value(cp->mode, key, node));
- } else {
- /* msg_warn("%s: unknown parameter", key); */
- return (0);
- }
-}
-
-/* expand_parameter_value - expand $name in parameter value */
-
-static const char *expand_parameter_value(int mode, const char *value,
- PC_PARAM_NODE *node)
-{
- const char *myname = "expand_parameter_value";
- static VSTRING *buf;
- int status;
- PC_EVAL_CTX eval_ctx;
-
- /*
- * Initialize.
- */
- if (buf == 0)
- buf = vstring_alloc(10);
-
- /*
- * Expand macros recursively.
- *
- * When expanding $name in "postconf -n" parameter values, don't limit the
- * search to only non-default parameter values.
- *
- * When expanding $name in "postconf -d" parameter values, do limit the
- * search to only default parameter values.
- */
-#define DONT_FILTER (char *) 0
-
- eval_ctx.mode = mode & ~SHOW_NONDEF;
- status = mac_expand(buf, value, MAC_EXP_FLAG_RECURSE, DONT_FILTER,
- expand_parameter_value_helper, (char *) &eval_ctx);
- if (status & MAC_PARSE_ERROR)
- msg_fatal("macro processing error");
- if (msg_verbose > 1) {
- if (strcmp(value, STR(buf)) != 0)
- msg_info("%s: expand %s -> %s", myname, value, STR(buf));
- else
- msg_info("%s: const %s", myname, value);
- }
- return (STR(buf));
-}
-
/* print_parameter - show specific parameter */
static void print_parameter(int mode, const char *name,
/*
* Use the default or actual value.
*/
- value = lookup_parameter_value(mode, name, node);
+ value = lookup_parameter_value(mode, name, (PC_MASTER_ENT *) 0, node);
/*
* Optionally expand $name in the parameter value. Print the result with
*/
if (value != 0) {
if ((mode & SHOW_EVAL) != 0 && PC_RAW_PARAMETER(node) == 0)
- value = expand_parameter_value(mode, value, node);
+ value = expand_parameter_value(mode, value, (PC_MASTER_ENT *) 0);
if (mode & SHOW_NAME) {
print_line(mode, "%s = %s\n", name, value);
} else {
/* print_master_line - print one master line */
-static void print_master_line(int mode, ARGV *argv)
+static void print_master_line(int mode, PC_MASTER_ENT *masterp)
{
- char *arg;
- char *aval;
+ char **argv = masterp->argv->argv;
+ const char *arg;
+ const char *aval;
+ int arg_len;
int line_len;
int field;
int in_daemon_options;
* least one-space column separation.
*/
for (line_len = 0, field = 0; field < PC_MASTER_MIN_FIELDS; field++) {
- arg = argv->argv[field];
+ arg = argv[field];
if (line_len > 0) {
do {
ADD_SPACE;
* have argument grouping preferences.
*/
in_daemon_options = 1;
- for ( /* void */ ; argv->argv[field] != 0; field++) {
- arg = argv->argv[field];
+ for ( /* void */ ; (arg = argv[field]) != 0; field++) {
+ arg_len = strlen(arg);
+ aval = 0;
if (in_daemon_options) {
/*
in_daemon_options = 0;
if ((mode & FOLD_LINE)
&& line_len > column_goal[PC_MASTER_MIN_FIELDS - 1]) {
- vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT);
- line_len = INDENT_LEN;
+ /* Force line wrap. */
+ line_len = LINE_LIMIT;
}
- }
+ } else {
- /*
- * Try to avoid breaking "-o name=value" over multiple lines if
- * it would fit on one line.
- */
- else if ((mode & FOLD_LINE)
- && line_len > INDENT_LEN && strcmp(arg, "-o") == 0
- && (aval = argv->argv[field + 1]) != 0
- && INDENT_LEN + 3 + strlen(aval) < LINE_LIMIT) {
- vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT);
- line_len = INDENT_LEN;
- ADD_TEXT(arg, strlen(arg));
- arg = aval;
- field += 1;
+ /*
+ * Process options with a value.
+ */
+ if (strcmp(arg, "-o") == 0
+ && (aval = argv[field + 1]) != 0
+ && (mode & SHOW_EVAL) != 0)
+ aval = expand_parameter_value(mode, aval, masterp);
+
+ /*
+ * Keep option and value on the same line.
+ */
+ if (aval)
+ arg_len += strlen(aval) + 1;
}
}
/*
- * Insert a line break when the next argument won't fit (unless, of
- * course, we just inserted a line break).
+ * Insert a line break when the next item won't fit.
*/
if (line_len > INDENT_LEN) {
if ((mode & FOLD_LINE) == 0
- || line_len + 1 + strlen(arg) < LINE_LIMIT) {
+ || line_len + 1 + arg_len < LINE_LIMIT) {
ADD_SPACE;
} else {
vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT);
}
}
ADD_TEXT(arg, strlen(arg));
+ if (aval) {
+ ADD_SPACE;
+ ADD_TEXT(aval, strlen(aval));
+ field += 1;
+ }
}
vstream_fputs("\n", VSTREAM_OUT);
}
void show_master(int mode, char **filters)
{
PC_MASTER_ENT *masterp;
- ARGV *argv;
ARGV *service_filter = 0;
/*
/*
* Iterate over the master table.
*/
- 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);
+ for (masterp = master_table; masterp->argv != 0; masterp++)
+ if ((service_filter == 0
+ || match_service_match(service_filter, masterp->name_space))
+ && ((mode & SHOW_NONDEF) == 0 || masterp->all_params != 0))
+ print_master_line(mode, masterp);
/*
* Cleanup.
node->flags = flags;
node->param_data = param_data;
node->convert_fn = convert_fn;
- node->cached_defval = 0;
return (node);
}
/* SCAN_USER_PARAMETER_VALUE - examine macro names in parameter value */
-#define SCAN_USER_PARAMETER_VALUE(value, local_scope) do { \
+#define SCAN_USER_PARAMETER_VALUE(value, class, scope) do { \
+ PC_PARAM_CTX _ctx; \
+ _ctx.local_scope = (scope); \
+ _ctx.param_class = (class); \
(void) mac_expand(NO_SCAN_RESULT, (value), MAC_EXP_FLAG_SCAN, \
- NO_SCAN_FILTER, flag_user_parameter, ((char *) (local_scope))); \
+ NO_SCAN_FILTER, flag_user_parameter, (char *) &_ctx); \
} while (0)
/* FLAG_USER_PARAMETER - flag user-defined name "valid" if it has name=value */
-#define FLAG_USER_PARAMETER(name, local_scope) do { \
- flag_user_parameter((name), NO_SCAN_MODE, ((char *) (local_scope))); \
+#define FLAG_USER_PARAMETER(name, class, scope) do { \
+ PC_PARAM_CTX _ctx; \
+ _ctx.local_scope = (scope); \
+ _ctx.param_class = (class); \
+ flag_user_parameter((name), NO_SCAN_MODE, (char *) &_ctx); \
} while (0)
/* convert_user_parameter - get user-defined parameter string value */
int unused_mode,
char *context)
{
- PC_MASTER_ENT *local_scope = (PC_MASTER_ENT *) context;
+ PC_PARAM_CTX *param_ctx = (PC_PARAM_CTX *) context;
+ PC_MASTER_ENT *local_scope = param_ctx->local_scope;
+ int param_class = param_ctx->param_class;
+ const char *source = local_scope ? MASTER_CONF_FILE : MAIN_CONF_FILE;
+ int user_supplied = 0;
/*
* If the name=value exists in the local (or global) name space, update
* compatibility after a feature name change.
*/
if (local_scope && dict_get(local_scope->all_params, mac_name)) {
+ user_supplied = 1;
/* $name in master.cf references name=value in master.cf. */
if (PC_PARAM_TABLE_LOCATE(local_scope->valid_names, mac_name) == 0) {
PC_PARAM_TABLE_ENTER(local_scope->valid_names, mac_name,
- PC_PARAM_FLAG_USER, PC_PARAM_NO_DATA,
+ param_class, PC_PARAM_NO_DATA,
convert_user_parameter);
if (msg_verbose)
msg_info("$%s in %s:%s validates %s=value in %s:%s",
local_scope->name_space);
}
} else if (mail_conf_lookup(mac_name) != 0) {
+ user_supplied = 1;
/* $name in main/master.cf references name=value in main.cf. */
if (PC_PARAM_TABLE_LOCATE(param_table, mac_name) == 0) {
- PC_PARAM_TABLE_ENTER(param_table, mac_name, PC_PARAM_FLAG_USER,
+ PC_PARAM_TABLE_ENTER(param_table, mac_name, param_class,
PC_PARAM_NO_DATA, convert_user_parameter);
if (msg_verbose) {
if (local_scope)
if (local_scope == 0) {
for (local_scope = master_table; local_scope->argv; local_scope++) {
if (local_scope->all_params != 0
- && dict_get(local_scope->all_params, mac_name) != 0
- /* $name in main.cf references name=value in master.cf. */
- && PC_PARAM_TABLE_LOCATE(local_scope->valid_names, mac_name) == 0) {
- PC_PARAM_TABLE_ENTER(local_scope->valid_names, mac_name,
- PC_PARAM_FLAG_USER, PC_PARAM_NO_DATA,
- convert_user_parameter);
- if (msg_verbose)
- msg_info("$%s in %s validates %s=value in %s:%s",
- mac_name, MAIN_CONF_FILE,
- mac_name, MASTER_CONF_FILE,
- local_scope->name_space);
+ && dict_get(local_scope->all_params, mac_name) != 0) {
+ user_supplied = 1;
+ /* $name in main.cf references name=value in master.cf. */
+ if (PC_PARAM_TABLE_LOCATE(local_scope->valid_names, mac_name) == 0) {
+ PC_PARAM_TABLE_ENTER(local_scope->valid_names, mac_name,
+ param_class, PC_PARAM_NO_DATA,
+ convert_user_parameter);
+ if (msg_verbose)
+ msg_info("$%s in %s validates %s=value in %s:%s",
+ mac_name, MAIN_CONF_FILE,
+ mac_name, MASTER_CONF_FILE,
+ local_scope->name_space);
+ }
}
}
}
+
+ /*
+ * Warn about a $name that has no user-supplied explicit value or
+ * Postfix-supplied default value. We don't enforce this for legacy DBMS
+ * parameters because they exist only for backwards compatibility, so we
+ * don't bother to figure out which parameters come without defaults.
+ */
+ if (user_supplied == 0 && (param_class & PC_PARAM_FLAG_DBMS) == 0
+ && PC_PARAM_TABLE_LOCATE(param_table, mac_name) == 0)
+ msg_warn("%s/%s: undefined parameter: %s",
+ var_config_dir, source, mac_name);
return (0);
}
const char *cparam_name;
const char *cparam_value;
PC_PARAM_NODE *node;
+ const char *source = local_scope ? MASTER_CONF_FILE : MAIN_CONF_FILE;
/*
* Flag parameter names in smtpd_restriction_classes as "valid", but only
if (local_scope == 0
&& htable_locate(rest_class_table, param_name) == 0)
htable_enter(rest_class_table, param_name, "");
- FLAG_USER_PARAMETER(param_name, local_scope);
+ FLAG_USER_PARAMETER(param_name, PC_PARAM_FLAG_USER, local_scope);
}
myfree(saved_class_list);
}
* "valid" in the local name space; 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.
+ *
+ * We delete name=value entries for read-only parameters, to maintain
+ * compatibility with Postfix programs that ignore such settings.
*/
if ((dict = dict_handle(dict_name)) == 0)
msg_panic("%s: parameter dictionary %s not found",
PC_PARAM_TABLE_ENTER(local_scope->valid_names, cparam_name,
PC_PARAM_FLAG_USER, PC_PARAM_NO_DATA,
convert_user_parameter);
- /* Skip "do not expand" parameters. */
- if ((node = PC_PARAM_TABLE_FIND(param_table, cparam_name)) != 0
- && PC_RAW_PARAMETER(node))
- continue;
- SCAN_USER_PARAMETER_VALUE(cparam_value, local_scope);
+ if ((node = PC_PARAM_TABLE_FIND(param_table, cparam_name)) != 0) {
+ if (PC_READONLY_PARAMETER(node)) {
+ msg_warn("%s/%s: read-only parameter assignment: %s=%s",
+ var_config_dir, source, cparam_name, cparam_value);
+ /* Can't use dict_del() with Postfix<2.10 htable_sequence(). */
+ if (dict_del(dict, cparam_name) != 0)
+ msg_panic("%s: can't delete %s/%s parameter entry for %s",
+ myname, var_config_dir, source, cparam_name);
+ continue;
+ }
+ /* Re-label legacy parameter as user-defined, so it's printed. */
+ if (PC_LEGACY_PARAMETER(node))
+ PC_PARAM_CLASS_OVERRIDE(node, PC_PARAM_FLAG_USER);
+ /* Skip "do not expand" parameters. */
+ if (PC_RAW_PARAMETER(node))
+ continue;
+ }
+ SCAN_USER_PARAMETER_VALUE(cparam_value, PC_PARAM_FLAG_USER, local_scope);
#ifdef LEGACY_DBMS_SUPPORT
register_dbms_parameters(cparam_value, flag_user_parameter,
local_scope);
PC_PARAM_INFO_NODE(*ht))) == 0)
msg_panic("%s: parameter %s has no default value",
myname, PC_PARAM_INFO_NAME(*ht));
- SCAN_USER_PARAMETER_VALUE(param_value, local_scope);
+ SCAN_USER_PARAMETER_VALUE(param_value, PC_PARAM_FLAG_USER, local_scope);
/* No need to scan default values for legacy DBMS configuration. */
}
myfree((char *) list);
+./postconf: warning: ./main.cf: undefined parameter: bar
config_directory = .
foo = yes
smtpd_restriction_classes = foo bar
+./postconf: warning: ./master.cf: undefined parameter: bar
+./postconf: warning: ./master.cf: undefined parameter: baz
foo inet - n n - 0 spawn
-o always_bcc=$bar$baz
zz_domain = whatever
./postconf: warning: ./main.cf: unused parameter: zz=$yy
./postconf: warning: ./main.cf: unused parameter: aa_domain=whatever
-./postconf: warning: ./main.cf: unused parameter: xx=proxy:ldap:foo
+./postconf: warning: ./main.cf: unused parameter: xx=ldap:foo
mysqlfoo_domain = bar
pgsqlfoo_domain = bar
sqlitefoo_domain = bar
-./postconf: warning: ./main.cf: unused parameter: sqlitexx=proxy:sqlite:sqlitefoo
-./postconf: warning: ./main.cf: unused parameter: pgsqlxx=proxy:pgsql:pgsqlfoo
+./postconf: warning: ./main.cf: unused parameter: sqlitexx=sqlite:sqlitefoo
+./postconf: warning: ./main.cf: unused parameter: pgsqlxx=pgsql:pgsqlfoo
./postconf: warning: ./main.cf: unused parameter: memcachefoo_domainx=bar
./postconf: warning: ./main.cf: unused parameter: sqlitefoo_domainx=bar
-./postconf: warning: ./main.cf: unused parameter: memcachexx=proxy:memcache:memcachefoo
-./postconf: warning: ./main.cf: unused parameter: mysqlxx=proxy:mysql:mysqlfoo
-./postconf: warning: ./main.cf: unused parameter: ldapxx=proxy:ldap:ldapfoo
+./postconf: warning: ./main.cf: unused parameter: memcachexx=memcache:memcachefoo
+./postconf: warning: ./main.cf: unused parameter: mysqlxx=mysql:mysqlfoo
+./postconf: warning: ./main.cf: unused parameter: ldapxx=ldap:ldapfoo
./postconf: warning: ./main.cf: unused parameter: ldapfoo_domainx=bar
./postconf: warning: ./main.cf: unused parameter: pgsqlfoo_domainx=bar
./postconf: warning: ./main.cf: unused parameter: mysqlfoo_domainx=bar
--- /dev/null
+./postconf: warning: ./main.cf: read-only parameter assignment: process_id=yyy
+./postconf: warning: ./main.cf: read-only parameter assignment: process_name=xxx
+mydestination = whatever
+process_name = postconf
--- /dev/null
+./postconf: warning: ./master.cf: read-only parameter assignment: process_id=bbb
+./postconf: warning: ./master.cf: read-only parameter assignment: process_name=aaa
+process_name = postconf
--- /dev/null
+./postconf: warning: ./main.cf: undefined parameter: virtual_mapx
+config_directory = .
+mydestination =
+virtual_alias_maps =
--- /dev/null
+whatever unix - n n - 0 other
+ -o mydestination=yyy -o always_bcc=ccc -o aaa=ccc
--- /dev/null
+bar unix - n n - 0 other -o aaa=ccc
--- /dev/null
+foo unix - n n - 0 other
+baz unix - n n - 0 other
HTABLE *table; /* hash table */
} DICT_HT;
+/* dict_ht_delete - delete hash-table entry */
+
+static int dict_ht_delete(DICT *dict, const char *name)
+{
+ DICT_HT *dict_ht = (DICT_HT *) dict;
+
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->flags & DICT_FLAG_FOLD_FIX) {
+ if (dict->fold_buf == 0)
+ dict->fold_buf = vstring_alloc(10);
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+ if (htable_locate(dict_ht->table, name) == 0) {
+ DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
+ } else {
+ htable_delete(dict_ht->table, name, myfree);
+ DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
+ }
+}
+
/* dict_ht_lookup - find hash-table entry */
static const char *dict_ht_lookup(DICT *dict, const char *name)
dict_ht = (DICT_HT *) dict_alloc(DICT_TYPE_HT, name, sizeof(*dict_ht));
dict_ht->dict.lookup = dict_ht_lookup;
dict_ht->dict.update = dict_ht_update;
+ dict_ht->dict.delete = dict_ht_delete;
dict_ht->dict.sequence = dict_ht_sequence;
dict_ht->dict.close = dict_ht_close;
dict_ht->dict.flags = dict_flags | DICT_FLAG_FIXED;
/* on the value of the "how" argument. Specify HTABLE_SEQ_FIRST
/* to start a new sequence, HTABLE_SEQ_NEXT to continue, and
/* HTABLE_SEQ_STOP to terminate a sequence early. The caller
-/* must not delete the current element.
+/* must not delete an element before it is visited.
/* RESTRICTIONS
/* A callback function should not modify the hash table that is
/* specified to its caller.
table = (HTABLE *) mymalloc(sizeof(HTABLE));
htable_size(table, size < 13 ? 13 : size);
- table->seq_element = 0;
+ table->seq_bucket = table->seq_element = 0;
return (table);
}
{
HTABLE_INFO *ht;
- if (table->used >= table->size && table->seq_element == 0)
+ if (table->used >= table->size)
htable_grow(table);
ht = (HTABLE_INFO *) mymalloc(sizeof(HTABLE_INFO));
ht->key = mystrdup(key);
}
myfree((char *) table->data);
table->data = 0;
+ if (table->seq_bucket)
+ myfree((char *) table->seq_bucket);
+ table->seq_bucket = 0;
myfree((char *) table);
}
}
switch (how) {
case HTABLE_SEQ_FIRST: /* start new sequence */
- table->seq_bucket = table->data;
- table->seq_element = table->seq_bucket[0];
- break;
+ if (table->seq_bucket)
+ myfree((char *) table->seq_bucket);
+ table->seq_bucket = htable_list(table);
+ table->seq_element = table->seq_bucket;
+ return (*(table->seq_element)++);
case HTABLE_SEQ_NEXT: /* next element */
- if (table->seq_element) {
- table->seq_element = table->seq_element->next;
- break;
- }
+ if (table->seq_element && *table->seq_element)
+ return (*(table->seq_element)++);
/* FALLTHROUGH */
default: /* terminate sequence */
- return (table->seq_element = 0);
+ if (table->seq_bucket) {
+ myfree((char *) table->seq_bucket);
+ table->seq_bucket = table->seq_element = 0;
+ }
+ return (0);
}
-
- while (table->seq_element == 0
- && ++(table->seq_bucket) < table->data + table->size)
- table->seq_element = table->seq_bucket[0];
- return (table->seq_element);
}
#ifdef TEST
int used; /* number of entries in table */
HTABLE_INFO **data; /* entries array, auto-resized */
HTABLE_INFO **seq_bucket; /* current sequence hash bucket */
- HTABLE_INFO *seq_element; /* current sequence element */
+ HTABLE_INFO **seq_element; /* current sequence element */
} HTABLE;
extern HTABLE *htable_create(int);