diff --git a/postfix/HISTORY b/postfix/HISTORY
index f245078d8..f1237ed8f 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -18198,3 +18198,13 @@ Apologies for any names omitted.
settings (for example, "postconf -x -o stress=whatever"
shows effective settings under overload). Files:
postconf/postconf.c, postconf/postconf_main.c.
+
+20121230
+
+ Cleanup: postconf(1) master.cf options parser. Files:
+ postconf/postconf_master.c, postconf/postconf_user.c.
+
+ Bugfix (omission in feature 20111106): the postconf(1)
+ master.cf options parser didn't support "clusters" of
+ command-line option letters. Files: postconf/postconf_master.c,
+ postconf/test40.ref.
diff --git a/postfix/WISHLIST b/postfix/WISHLIST
index 2fad322d2..1f5052d1e 100644
--- a/postfix/WISHLIST
+++ b/postfix/WISHLIST
@@ -13,6 +13,9 @@ Wish list:
Should postconf -o refuse to work without the -x option?
+ Make 30s caching (feature 20070414) configurable, such that
+ 0 means no caching.
+
Make errno white/blacklist for getpwnam_r etc. and mailbox
write errors.
diff --git a/postfix/html/postconf.1.html b/postfix/html/postconf.1.html
index edc146836..d17d96e93 100644
--- a/postfix/html/postconf.1.html
+++ b/postfix/html/postconf.1.html
@@ -150,7 +150,8 @@ POSTCONF(1) POSTCONF(1)
creating a file named filename.lock. The
application is expected to remove its own
lock file, as well as stale lock files that
- were left behind after abnormal termination.
+ were left behind after abnormal program ter-
+ mination.
-m List the names of all supported lookup table types.
In Postfix configuration files, lookup tables are
diff --git a/postfix/man/man1/postconf.1 b/postfix/man/man1/postconf.1
index c45a2d7ee..269c9ca64 100644
--- a/postfix/man/man1/postconf.1
+++ b/postfix/man/man1/postconf.1
@@ -144,7 +144,8 @@ A kernel-based advisory locking method for local and remote files.
An application-level locking method. An application locks a file
named \fIfilename\fR by creating a file named \fIfilename\fB.lock\fR.
The application is expected to remove its own lock file, as well as
-stale lock files that were left behind after abnormal termination.
+stale lock files that were left behind after abnormal program
+termination.
.RE
.IP \fB-m\fR
List the names of all supported lookup table types. In Postfix
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 9e5aa210c..61019449d 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 "20121227"
+#define MAIL_RELEASE_DATE "20130101"
#define MAIL_VERSION_NUMBER "2.10"
#ifdef SNAPSHOT
diff --git a/postfix/src/postconf/Makefile.in b/postfix/src/postconf/Makefile.in
index 41423d32f..66c565cc1 100644
--- a/postfix/src/postconf/Makefile.in
+++ b/postfix/src/postconf/Makefile.in
@@ -45,7 +45,7 @@ test: $(TESTPROG)
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 test34 test35 test36 test37 test38 test39
+ test31 test32 test33 test34 test35 test36 test37 test38 test39 test40
root_tests:
@@ -527,6 +527,17 @@ test39: $(PROG) test39.ref
diff test39.ref test39.tmp
rm -f main.cf master.cf test39.tmp
+test40: $(PROG) test40.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo ' -voaaa=bbb' >> master.cf
+ echo ' -vo ccc=$$aaa' >> master.cf
+ echo ' -v -oddd=$$ccc' >> master.cf
+ ./$(PROG) -Mfxc . unix >test40.tmp 2>&1
+ diff test40.ref test40.tmp
+ rm -f main.cf master.cf test40.tmp
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c
index 71969edc3..4e3ae9a42 100644
--- a/postfix/src/postconf/postconf.c
+++ b/postfix/src/postconf/postconf.c
@@ -138,7 +138,8 @@
/* An application-level locking method. An application locks a file
/* named \fIfilename\fR by creating a file named \fIfilename\fB.lock\fR.
/* The application is expected to remove its own lock file, as well as
-/* stale lock files that were left behind after abnormal termination.
+/* stale lock files that were left behind after abnormal program
+/* termination.
/* .RE
/* .IP \fB-m\fR
/* List the names of all supported lookup table types. In Postfix
@@ -584,7 +585,7 @@ int main(int argc, char **argv)
register_builtin_parameters(basename(argv[0]), getpid());
register_service_parameters();
register_user_parameters();
- show_master(cmd_mode, argv + optind);
+ show_master(VSTREAM_OUT, cmd_mode, argv + optind);
}
/*
@@ -631,7 +632,7 @@ int main(int argc, char **argv)
/*
* Show the requested values.
*/
- show_parameters(cmd_mode, param_class, argv + optind);
+ show_parameters(VSTREAM_OUT, cmd_mode, param_class, argv + optind);
/*
* Flag unused parameters. This makes no sense with "postconf -d",
diff --git a/postfix/src/postconf/postconf.h b/postfix/src/postconf/postconf.h
index ca575c125..8b7bca5ad 100644
--- a/postfix/src/postconf/postconf.h
+++ b/postfix/src/postconf/postconf.h
@@ -142,7 +142,7 @@ extern void set_config_dir(void);
*/
extern void read_parameters(void);
extern void set_parameters(char **);
-extern void show_parameters(int, int, char **);
+extern void show_parameters(VSTREAM *, int, int, char **);
/*
* postconf_edit.c
@@ -152,8 +152,9 @@ extern void edit_parameters(int, int, char **);
/*
* postconf_master.c.
*/
+extern const char daemon_options_expecting_value[];
extern void read_master(int);
-extern void show_master(int, char **);
+extern void show_master(VSTREAM *, int, char **);
#define WARN_ON_OPEN_ERROR 0
#define FAIL_ON_OPEN_ERROR 1
diff --git a/postfix/src/postconf/postconf_lookup.c b/postfix/src/postconf/postconf_lookup.c
index dc3c6964b..8085af249 100644
--- a/postfix/src/postconf/postconf_lookup.c
+++ b/postfix/src/postconf/postconf_lookup.c
@@ -35,12 +35,12 @@
/*
/* 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.
+/* The result value is a pointer to storage in a user-supplied
+/* buffer, or in a buffer that is overwritten with each call.
/*
/* Arguments:
/* .IP buf
-/* Null pointer, or pointer to output storage.
+/* Null buffer pointer, or pointer to user-supplied buffer.
/* .IP mode
/* Bit-wise OR of zero or one of the following (other flags
/* are ignored):
@@ -48,7 +48,7 @@
/* .IP SHOW_DEFS
/* Search built-in default parameter settings only.
/* .IP SHOW_NONDEF
-/* Search local (master.cf) or global (main.cf) name=value
+/* Search local (master.cf) and global (main.cf) name=value
/* parameter settings only.
/* .RE
/* .IP name
@@ -56,11 +56,11 @@
/* .IP value
/* The parameter value where $name should be expanded.
/* .IP local_scope
-/* Null pointer, or pointer to master.cf entry with local
-/* name=value settings.
+/* Pointer to master.cf entry with local name=value settings,
+/* or a null pointer (i.e. no local parameter lookup).
/* .IP node
-/* Null pointer, or global default setting for the named
-/* parameter.
+/* Global default value for the named parameter, or a null
+/* pointer (i.e. do the global default lookup anyway).
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* LICENSE
@@ -107,9 +107,9 @@ const char *lookup_parameter_value(int mode, const char *name,
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.
+ * 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
diff --git a/postfix/src/postconf/postconf_main.c b/postfix/src/postconf/postconf_main.c
index 8b89476ee..d94c4a6e6 100644
--- a/postfix/src/postconf/postconf_main.c
+++ b/postfix/src/postconf/postconf_main.c
@@ -8,7 +8,8 @@
/*
/* void read_parameters()
/*
-/* void show_parameters(mode, param_class, names)
+/* void show_parameters(fp, mode, param_class, names)
+/* VSTREAM *fp;
/* int mode;
/* int param_class;
/* char **names;
@@ -18,10 +19,12 @@
/* set_parameters() takes an array of \fIname=value\fR pairs
/* and overrides settings read with read_parameters().
/*
-/* show_parameters() writes main.cf parameters to the standard
+/* show_parameters() writes main.cf parameters to the specified
/* output stream.
/*
/* Arguments:
+/* .IP fp
+/* Output stream.
/* .IP mode
/* Bit-wise OR of zero or more of the following:
/* .RS
@@ -128,7 +131,7 @@ void set_parameters(char **name_val_array)
/* print_line - show line possibly folded, and with normalized whitespace */
-static void print_line(int mode, const char *fmt,...)
+static void print_line(VSTREAM *fp, int mode, const char *fmt,...)
{
va_list ap;
static VSTRING *buf = 0;
@@ -166,22 +169,22 @@ static void print_line(int mode, const char *fmt,...)
*next++ = 0;
if (word_len > 0 && line_len > 0) {
if ((mode & FOLD_LINE) == 0 || line_len + word_len < LINE_LIMIT) {
- vstream_fputs(" ", VSTREAM_OUT);
+ vstream_fputs(" ", fp);
line_len += 1;
} else {
- vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT);
+ vstream_fputs("\n" INDENT_TEXT, fp);
line_len = INDENT_LEN;
}
}
- vstream_fputs(start, VSTREAM_OUT);
+ vstream_fputs(start, fp);
line_len += word_len;
}
- vstream_fputs("\n", VSTREAM_OUT);
+ vstream_fputs("\n", fp);
}
/* print_parameter - show specific parameter */
-static void print_parameter(int mode, const char *name,
+static void print_parameter(VSTREAM *fp, int mode, const char *name,
PC_PARAM_NODE *node)
{
const char *value;
@@ -200,12 +203,12 @@ static void print_parameter(int mode, const char *name,
value = expand_parameter_value((VSTRING *) 0, mode, value,
(PC_MASTER_ENT *) 0);
if (mode & SHOW_NAME) {
- print_line(mode, "%s = %s\n", name, value);
+ print_line(fp, mode, "%s = %s\n", name, value);
} else {
- print_line(mode, "%s\n", value);
+ print_line(fp, mode, "%s\n", value);
}
if (msg_verbose)
- vstream_fflush(VSTREAM_OUT);
+ vstream_fflush(fp);
}
}
@@ -222,7 +225,7 @@ static int comp_names(const void *a, const void *b)
/* show_parameters - show parameter info */
-void show_parameters(int mode, int param_class, char **names)
+void show_parameters(VSTREAM *fp, int mode, int param_class, char **names)
{
PC_PARAM_INFO **list;
PC_PARAM_INFO **ht;
@@ -237,7 +240,7 @@ void show_parameters(int mode, int param_class, char **names)
qsort((char *) list, param_table->used, sizeof(*list), comp_names);
for (ht = list; *ht; ht++)
if (param_class & PC_PARAM_INFO_NODE(*ht)->flags)
- print_parameter(mode, PC_PARAM_INFO_NAME(*ht),
+ print_parameter(fp, mode, PC_PARAM_INFO_NAME(*ht),
PC_PARAM_INFO_NODE(*ht));
myfree((char *) list);
return;
@@ -250,7 +253,7 @@ void show_parameters(int mode, int param_class, char **names)
if ((node = PC_PARAM_TABLE_FIND(param_table, *namep)) == 0) {
msg_warn("%s: unknown parameter", *namep);
} else {
- print_parameter(mode, *namep, node);
+ print_parameter(fp, mode, *namep, node);
}
}
}
diff --git a/postfix/src/postconf/postconf_master.c b/postfix/src/postconf/postconf_master.c
index 8e16a2a5c..251d94eb8 100644
--- a/postfix/src/postconf/postconf_master.c
+++ b/postfix/src/postconf/postconf_master.c
@@ -6,22 +6,30 @@
/* SYNOPSIS
/* #include
/*
+/* const char daemon_options_expecting_value[];
+/*
/* void read_master(fail_on_open)
/* int fail_on_open;
/*
-/* void show_master(mode, filters)
+/* void show_master(fp, mode, filters)
+/* VSTREAM *fp;
/* int mode;
/* char **filters;
/* DESCRIPTION
/* read_master() reads entries from master.cf into memory.
/*
/* show_master() writes the entries in the master.cf file
-/* to standard output.
+/* to the specified stream.
+/*
+/* daemon_options_expecting_value[] is an array of master.cf
+/* daemon command-line options that expect an option value.
/*
/* Arguments
/* .IP fail_on_open
/* Specify FAIL_ON_OPEN if open failure is a fatal error,
/* WARN_ON_OPEN if a warning should be logged instead.
+/* .IP fp
+/* Output stream.
/* .IP mode
/* If the FOLD_LINE flag is set, show_master() wraps long
/* output lines.
@@ -66,6 +74,8 @@
#include
+const char daemon_options_expecting_value[] = "o";
+
#define STR(x) vstring_str(x)
/* normalize_options - bring options into canonical form */
@@ -74,6 +84,8 @@ static void normalize_options(ARGV *argv)
{
int field;
char *arg;
+ char *cp;
+ char *junk;
/*
* Normalize options to simplify later processing.
@@ -82,18 +94,29 @@ static void normalize_options(ARGV *argv)
arg = argv->argv[field];
if (arg[0] != '-' || strcmp(arg, "--") == 0)
break;
- if (strncmp(arg, "-o", 2) == 0) {
- if (arg[2] != 0) {
- /* Split "-oname=value" into "-o" "name=value". */
- argv_insert_one(argv, field + 1, arg + 2);
- argv_replace_one(argv, field, "-o");
- /* arg is now a dangling pointer. */
- field += 1;
- } else if (argv->argv[field + 1] != 0) {
- /* Already in "-o" "name=value" form. */
- field += 1;
+ for (cp = arg + 1; *cp; cp++) {
+ if (strchr(daemon_options_expecting_value, *cp) != 0
+ && cp > arg + 1) {
+ /* Split "-stuffo" into "-stuff" and "-o". */
+ junk = concatenate("-", cp, (char *) 0);
+ argv_insert_one(argv, field + 1, junk);
+ myfree(junk);
+ *cp = 0;
+ break;
}
}
+ if (strchr(daemon_options_expecting_value, arg[1]) == 0)
+ /* Option requires no value. */
+ continue;
+ if (arg[2] != 0) {
+ /* Split "-oname=value" into "-o" "name=value". */
+ argv_insert_one(argv, field + 1, arg + 2);
+ arg[2] = 0;
+ field += 1;
+ } else if (argv->argv[field + 1] != 0) {
+ /* Already in "-o" "name=value" form. */
+ field += 1;
+ }
}
}
@@ -176,7 +199,7 @@ void read_master(int fail_on_open_error)
/* print_master_line - print one master line */
-static void print_master_line(int mode, PC_MASTER_ENT *masterp)
+static void print_master_line(VSTREAM *fp, int mode, PC_MASTER_ENT *masterp)
{
char **argv = masterp->argv->argv;
const char *arg;
@@ -197,7 +220,7 @@ static void print_master_line(int mode, PC_MASTER_ENT *masterp)
};
#define ADD_TEXT(text, len) do { \
- vstream_fputs(text, VSTREAM_OUT); line_len += len; } \
+ vstream_fputs(text, fp); line_len += len; } \
while (0)
#define ADD_SPACE ADD_TEXT(" ", 1)
@@ -237,13 +260,18 @@ static void print_master_line(int mode, PC_MASTER_ENT *masterp)
/* Force line wrap. */
line_len = LINE_LIMIT;
}
- } else {
+ }
+
+ /*
+ * Special processing for options that require a value.
+ */
+ else if (strchr(daemon_options_expecting_value, arg[1]) != 0
+ && (aval = argv[field + 1]) != 0) {
/*
- * Process options with a value.
+ * Optionally, expand $name in parameter value.
*/
if (strcmp(arg, "-o") == 0
- && (aval = argv[field + 1]) != 0
&& (mode & SHOW_EVAL) != 0)
aval = expand_parameter_value((VSTRING *) 0, mode,
aval, masterp);
@@ -251,8 +279,7 @@ static void print_master_line(int mode, PC_MASTER_ENT *masterp)
/*
* Keep option and value on the same line.
*/
- if (aval)
- arg_len += strlen(aval) + 1;
+ arg_len += strlen(aval) + 1;
}
}
@@ -264,7 +291,7 @@ static void print_master_line(int mode, PC_MASTER_ENT *masterp)
|| line_len + 1 + arg_len < LINE_LIMIT) {
ADD_SPACE;
} else {
- vstream_fputs("\n" INDENT_TEXT, VSTREAM_OUT);
+ vstream_fputs("\n" INDENT_TEXT, fp);
line_len = INDENT_LEN;
}
}
@@ -275,12 +302,12 @@ static void print_master_line(int mode, PC_MASTER_ENT *masterp)
field += 1;
}
}
- vstream_fputs("\n", VSTREAM_OUT);
+ vstream_fputs("\n", fp);
}
/* show_master - show master.cf entries */
-void show_master(int mode, char **filters)
+void show_master(VSTREAM *fp, int mode, char **filters)
{
PC_MASTER_ENT *masterp;
ARGV *service_filter = 0;
@@ -298,7 +325,7 @@ void show_master(int mode, char **filters)
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);
+ print_master_line(fp, mode, masterp);
/*
* Cleanup.
diff --git a/postfix/src/postconf/postconf_user.c b/postfix/src/postconf/postconf_user.c
index 195c81739..7fc659c4c 100644
--- a/postfix/src/postconf/postconf_user.c
+++ b/postfix/src/postconf/postconf_user.c
@@ -87,7 +87,6 @@ static HTABLE *rest_class_table;
*/
#define NO_SCAN_RESULT ((VSTRING *) 0)
#define NO_SCAN_FILTER ((char *) 0)
-#define NO_SCAN_MODE (0)
/* SCAN_USER_PARAMETER_VALUE - examine macro names in parameter value */
@@ -189,7 +188,7 @@ static const char *flag_user_parameter(const char *mac_name,
return (0);
}
-/* flag_user_parameter_wrapper - max_expand call-back helper */
+/* flag_user_parameter_wrapper - mac_expand call-back helper */
static const char *flag_user_parameter_wrapper(const char *mac_name,
int unused_mode,
@@ -334,6 +333,7 @@ void register_user_parameters(void)
PC_MASTER_ENT *masterp;
ARGV *argv;
char *arg;
+ char *aval;
int field;
char *saved_arg;
char *param_name;
@@ -363,13 +363,16 @@ void register_user_parameters(void)
arg = argv->argv[field];
if (arg[0] != '-' || strcmp(arg, "--") == 0)
break;
- if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) {
- saved_arg = mystrdup(arg);
+ if (strchr(daemon_options_expecting_value, arg[1]) == 0
+ || (aval = argv->argv[field + 1]) == 0)
+ continue;
+ if (strcmp(arg, "-o") == 0) {
+ saved_arg = mystrdup(aval);
if (split_nameval(saved_arg, ¶m_name, ¶m_value) == 0)
dict_update(masterp->name_space, param_name, param_value);
myfree(saved_arg);
- field += 1;
}
+ field += 1;
}
if ((dict = dict_handle(masterp->name_space)) != 0) {
masterp->all_params = dict;
diff --git a/postfix/src/postconf/test40.ref b/postfix/src/postconf/test40.ref
new file mode 100644
index 000000000..d7ec1b9d9
--- /dev/null
+++ b/postfix/src/postconf/test40.ref
@@ -0,0 +1,2 @@
+foo unix - n n - 0 other -v -o aaa=bbb -v
+ -o ccc=bbb -v -o ddd=bbb