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