aboutsummaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c429
1 files changed, 297 insertions, 132 deletions
diff --git a/src/main.c b/src/main.c
index 7fe40dbc..64c50468 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,21 +1,21 @@
/* This file is part of Mailfromd.
- Copyright (C) 2005-2019 Sergey Poznyakoff
+ Copyright (C) 2005-2024 Sergey Poznyakoff
- This program is free software; you can redistribute it and/or modify
+ Mailfromd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
- This program is distributed in the hope that it will be useful,
+ Mailfromd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ along with mailfromd. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
@@ -28,12 +28,14 @@
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
+#include <termios.h>
+#include <sys/ioctl.h>
#include <mailutils/mailutils.h>
#include <mailutils/server.h>
#include <mailutils/syslog.h>
#include <mailutils/cli.h>
#include <mailutils/dbm.h>
@@ -50,35 +52,35 @@
/* Configurable options */
int mode = MAILFROMD_DAEMON; /* Default operation mode */
enum smtp_state test_state = smtp_state_envfrom; /* State for --test mode */
int need_script = 1; /* Set if the current mode requires reading the
script file */
-char *script_file = DEFAULT_SCRIPT_FILE;
+char *script_file;
int script_check; /* Check config file syntax and exit */
extern int yy_flex_debug; /* Enable tracing the lexical analyzer */
int script_ydebug; /* Enable tracing the parser */
int script_dump_tree; /* Dump created config tree to stdout */
int script_dump_code; /* Dump disassembled code to stdout */
int script_dump_macros; /* Dump used Sendmail macros */
int script_dump_xref; /* Dump cross-reference */
int preprocess_option; /* Only preprocess the sources */
int location_column_option; /* Print column numbers in error locations */
-char *ext_pp = DEF_EXT_PP; /* External preprocessor to use */
char *ext_pp_options;
int ext_pp_options_given;
int do_trace; /* Enable tracing configuration */
unsigned optimization_level = 1; /* Optimization level */
int stack_trace_option; /* Print stack traces on runtime errors */
char *main_function_name = "main";
char *callout_server_url;
+char *echo_output; /* Output file for 'echo' statements. */
mu_stream_t mf_strecho; /* Output stream for 'echo' statements */
#define ARG_UNSET (-1)
static int trace_option = ARG_UNSET;
static mu_list_t trace_modules;
@@ -99,13 +101,13 @@ add_pp_option(const char *opt, const char *arg)
ext_pp_options = mu_alloc(len + 1);
ext_pp_options[0] = 0;
}
strcat(ext_pp_options, " ");
strcat(ext_pp_options, opt);
strcat(ext_pp_options, arg);
-}
+}
void
pp_define(const char *symbol)
{
add_pp_option("-D", symbol);
}
@@ -331,16 +333,15 @@ opt_daemon(struct mu_parseopt *po, struct mu_option *op,
{
mode = MAILFROMD_DAEMON;
need_script = 1;
}
static void
-opt_include_dir(struct mu_parseopt *po, struct mu_option *op,
- char const *arg)
+opt_path_add(struct mu_parseopt *po, struct mu_option *op, char const *arg)
{
- add_include_dir(arg);
+ pathbuf_add((struct pathbuf *)op->opt_ptr, arg);
}
static void
opt_milter_socket(struct mu_parseopt *po, struct mu_option *op,
char const *arg)
{
@@ -404,29 +405,51 @@ opt_relayed_domain_file(struct mu_parseopt *po, struct mu_option *op,
if (!relayed_domain_files)
mu_list_create(&relayed_domain_files);
mu_list_append(relayed_domain_files, mu_strdup(arg));
}
static void
-opt_clear_ext_pp(struct mu_parseopt *po, struct mu_option *op, char const *arg)
+opt_disable_preprocessor(struct mu_parseopt *po, struct mu_option *op, char const *arg)
{
- ext_pp = NULL;
+ preprocessor.enabled = 0;
+}
+
+static void
+opt_preprocessor(struct mu_parseopt *po, struct mu_option *op, char const *arg)
+{
+ preprocessor.enabled = 1;
+ if (arg)
+ preprocessor.command = (char*) arg;
+ else if (!preprocessor.command) {
+ mu_error(_("preprocessor options given, "
+ "but no default preprocessor defined: "
+ "use the --preprocessor option"));
+ exit(EX_USAGE);
+ }
}
static void
opt_define(struct mu_parseopt *po, struct mu_option *op, char const *arg)
{
- ext_pp_options_given = 1;
- add_pp_option("-D", arg);
+ if (preprocessor.pass_defines) {
+ ext_pp_options_given = 1;
+ add_pp_option("-D", arg);
+ } else
+ mu_error("%s",
+ _("Your configuration file disables passing defines to the preprocessor"));
}
static void
opt_undefine(struct mu_parseopt *po, struct mu_option *op, char const *arg)
{
- ext_pp_options_given = 1;
- add_pp_option("-U", arg);
+ if (preprocessor.pass_defines) {
+ ext_pp_options_given = 1;
+ add_pp_option("-U", arg);
+ } else
+ mu_error("%s",
+ _("Your configuration file disables passing defines to the preprocessor"));
}
static void
opt_set_milter_timeout(struct mu_parseopt *po, struct mu_option *op,
char const *arg)
{
@@ -552,16 +575,20 @@ static struct mu_option mailfromd_options[] = {
mu_c_void },
{ "load-dir", 'L', N_("DIR"), MU_OPTION_HIDDEN,
N_("add DIR to the load path"),
mu_c_void },
MU_OPTION_GROUP(N_("General options")),
- { "include", 'I', N_("DIR"), MU_OPTION_DEFAULT,
+ { "include-path", 'I', N_("DIR"), MU_OPTION_DEFAULT,
N_("add the directory DIR to the list of directories to be "
"searched for header files"),
- mu_c_string, NULL, opt_include_dir },
+ mu_c_string, &include_path, opt_path_add },
+ { "module-path", 'P', N_("DIR"), MU_OPTION_DEFAULT,
+ N_("add the directory DIR to the list of directories to be "
+ "searched for MFL module files"),
+ mu_c_string, &module_path, opt_path_add },
{ "port", 'p', N_("STRING"), MU_OPTION_DEFAULT,
N_("set communication socket"),
mu_c_string, NULL, opt_milter_socket },
{ "milter-socket", 0, NULL, MU_OPTION_ALIAS },
{ "callout-socket", 0, N_("STRING"), MU_OPTION_DEFAULT,
N_("set callout socket"),
@@ -578,20 +605,23 @@ static struct mu_option mailfromd_options[] = {
{ "relayed-domain-file", 0, N_("FILE"), MU_OPTION_DEFAULT,
N_("read relayed domains from FILE"),
mu_c_string, NULL, opt_relayed_domain_file },
{ "resolv-conf-file", 0, N_("FILE"), MU_OPTION_DEFAULT,
N_("read resolver configuration from FILE"),
mu_c_string, &resolv_conf_file },
+ { "echo", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL,
+ N_("divert output of the \"echo\" instruction to FILE"),
+ mu_c_string, &echo_output, NULL, "-" },
MU_OPTION_GROUP(N_("Preprocessor options")),
- { "preprocessor", 0, N_("COMMAND"), MU_OPTION_DEFAULT,
+ { "preprocessor", 0, N_("COMMAND"), MU_OPTION_ARG_OPTIONAL,
N_("use command as external preprocessor"),
- mu_c_string, &ext_pp },
+ mu_c_string, NULL, opt_preprocessor },
{ "no-preprocessor", 0, NULL, MU_OPTION_DEFAULT,
N_("disable the use of external preprocessor"),
- mu_c_string, NULL, opt_clear_ext_pp },
+ mu_c_string, NULL, opt_disable_preprocessor },
{ "define", 'D', N_("NAME[=VALUE]"), MU_OPTION_DEFAULT,
N_("define a preprocessor symbol NAME as having VALUE, or empty"),
mu_c_string, NULL, opt_define },
{ "undefine", 'U', N_("NAME"), MU_OPTION_DEFAULT,
N_("undefine a preprocessor symbol NAME"),
mu_c_string, NULL, opt_undefine },
@@ -732,52 +762,42 @@ cb_set_variable(void *data, mu_config_value_t *arg)
mu_locus_range_deinit(&locus);
free(alloc_str);
return 0;
}
static int
-cb_include_path(void *data, mu_config_value_t *val)
+cb_pathbuf_add(void *data, mu_config_value_t *val)
{
int i, rc = 0;
- struct mu_wordsplit ws;
mu_iterator_t itr;
-
+ struct pathbuf *pb = data;
+
switch (val->type) {
case MU_CFG_STRING:
- ws.ws_delim = ":";
- if (mu_wordsplit(val->v.string, &ws,
- MU_WRDSF_NOVAR |
- MU_WRDSF_NOCMD | MU_WRDSF_DELIM)) {
- mu_error("mu_wordsplit: %s",
- mu_wordsplit_strerror(&ws));
- return 1;
- }
- for (i = 0; i < ws.ws_wordc; i++)
- add_include_dir(ws.ws_wordv[i]);
- mu_wordsplit_free(&ws);
+ pathbuf_add(pb, val->v.string);
break;
case MU_CFG_ARRAY:
for (i = 0; i < val->v.arg.c; i++) {
if (mu_cfg_assert_value_type(&val->v.arg.v[i],
MU_CFG_STRING))
return 1;
- add_include_dir(val->v.arg.v[i].v.string);
+ pathbuf_add(pb, val->v.arg.v[i].v.string);
}
break;
case MU_CFG_LIST:
mu_list_get_iterator(val->v.list, &itr);
for (mu_iterator_first(itr);
!mu_iterator_is_done(itr); mu_iterator_next(itr)) {
mu_config_value_t *pval;
mu_iterator_current(itr, (void*) &pval);
rc = mu_cfg_assert_value_type(pval, MU_CFG_STRING);
if (rc)
break;
- add_include_dir(pval->v.string);
+ pathbuf_add(pb, pval->v.string);
}
mu_iterator_destroy(&itr);
}
return rc;
}
@@ -805,46 +825,61 @@ cb_trace_program(void *data, mu_config_value_t *val)
break;
}
return rc;
}
static int
+cfg_load_relay_file(void *item, void *data)
+{
+ mu_config_value_t *val = item;
+ if (mu_cfg_assert_value_type(val, MU_CFG_STRING) == 0)
+ read_domain_file(val->v.string);
+ return 0;
+}
+
+static int
cb_relayed_domain_file(void *data, mu_config_value_t *val)
{
switch (val->type) {
case MU_CFG_STRING:
read_domain_file(val->v.string);
break;
case MU_CFG_LIST:
- mu_list_foreach(val->v.list, load_relay_file, NULL);
+ mu_list_foreach(val->v.list, cfg_load_relay_file, NULL);
break;
default:
mu_error (_("expected string or list of strings"));
}
return 0;
}
struct mu_cfg_param mf_cfg_param[] = {
{ ".mfd:server", mu_cfg_section, NULL, 0, NULL, NULL },
+ { "resolver", mu_cfg_section, NULL, 0, NULL, NULL },
{ "stack-trace", mu_c_bool, &stack_trace_option, 0, NULL,
N_("Dump stack traces on runtime errors.") },
{ "milter-timeout", mu_cfg_callback, NULL, 0, cb_milter_timeout,
N_("Set milter timeout."),
N_("time: interval") },
{ "callout-url", mu_c_string, &callout_server_url, 0, NULL,
N_("Sets the URL of the default callout server."),
N_("url") },
- { "include-path", mu_cfg_callback, NULL, 0, cb_include_path,
+ { "include-path", mu_cfg_callback, &include_path, 0, cb_pathbuf_add,
N_("Add directories to the list of directories to be searched for "
"header files. Argument is a list of directory names "
"separated by colons."),
N_("path: string") },
+ { "module-path", mu_cfg_callback, &module_path, 0, cb_pathbuf_add,
+ N_("Add directories to the list of directories to be searched for "
+ "MFL modules. Argument is a list of directory names "
+ "separated by colons."),
+ N_("path: string") },
{ "setvar", mu_cfg_callback, NULL, 0, cb_set_variable,
N_("Initialize a mailfromd variable <var> to <value>."),
N_("var: string> <value: string-or-number") },
{ "script-file", mu_c_string, &script_file, 0, NULL,
N_("Read filter script from <file>."),
N_("file") },
@@ -856,22 +891,13 @@ struct mu_cfg_param mf_cfg_param[] = {
{ "relayed-domain-file", mu_cfg_callback, NULL, 0,
cb_relayed_domain_file,
N_("Read relayed domain names from the file"),
N_("file: string") },
- { "database", mu_cfg_section, NULL },
-
- { "lock-retry-count", mu_cfg_callback, NULL, 0,
- config_cb_lock_retry_count,
- N_("Retry acquiring DBM file lock this number of times.") },
- { "lock-retry-timeout", mu_cfg_callback, NULL, 0,
- config_cb_lock_retry_timeout,
- N_("Set the time span between the two DBM locking attempts."),
- N_("time: interval") },
-
+ { "preprocessor", mu_cfg_section, NULL },
{ "runtime", mu_cfg_section, NULL },
{ NULL }
};
@@ -922,13 +948,12 @@ mf_runtime_param_finish()
break;
}
}
}
}
-
/* Auxiliary functions */
unsigned keyword_column = 0;
unsigned header_column = 2;
unsigned value_column = 32;
unsigned right_margin = 79;
@@ -967,23 +992,18 @@ db_format_enumerator(struct db_format *fmt, void *data)
mu_stream_printf(str, "%lu\n", fmt->expire_interval);
}
return 0;
}
static void
-list_db_formats(mu_stream_t str, const char *pfx)
+print_supported_dbtypes(mu_stream_t str)
{
mu_iterator_t itr;
int rc;
const char *defdb = DEFAULT_DB_TYPE;
- set_column(str, keyword_column);
- mu_stream_printf(str, "%s:", pfx);
-
- set_column(str, value_column);
-
rc = mu_dbm_impl_iterator(&itr);
if (rc) {
mu_stream_printf(str, "%s\n", _("unknown"));
mu_error("%s", mu_strerror(rc));
} else {
int i;
@@ -998,33 +1018,73 @@ list_db_formats(mu_stream_t str, const char *pfx)
defdb = impl->_dbm_name;
mu_stream_printf(str, "%s", impl->_dbm_name);
}
mu_stream_write(str, "\n", 1, NULL);
mu_iterator_destroy(&itr);
}
-
+//FIXME
set_column(str, keyword_column);
mu_stream_printf(str, "%s:", "default database type");
set_column(str, value_column);
- mu_stream_printf(str, "%s\n", defdb);
+ mu_stream_write(str, defdb, strlen(defdb), NULL);
}
struct string_value {
char const *kw;
int type;
union {
char *s_const;
char **s_var;
- char *(*s_func) (void);
+ char const *(*s_func) (void);
+ void (*s_print) (mu_stream_t);
} data;
};
-static char *
-string_preprocessor (void)
+char const *
+string_preprocessor(void)
+{
+ return (preprocessor.enabled && preprocessor.command)
+ ? preprocessor.command : "none";
+}
+
+static void
+print_optional_values(mu_stream_t str)
+{
+ static char *features[] = {
+#if defined WITH_DKIM
+ "DKIM",
+#endif
+#if defined WITH_GEOIP2
+ "GeoIP2",
+#endif
+#if defined WITH_MFMOD
+ "mfmod",
+#endif
+#if defined WITH_MAILUTILS_GNUTLS
+ "STARTTLS",
+#endif
+ NULL
+ };
+
+ if (features[0]) {
+ int i;
+
+ mu_stream_write(str, features[0], strlen(features[0]), NULL);
+ for (i = 1; features[i]; i++) {
+ mu_stream_write(str, ", ", 2, NULL);
+ mu_stream_write(str, features[i], strlen(features[i]), NULL);
+ }
+ }
+}
+
+static void
+print_script_file(mu_stream_t str)
{
- return ext_pp ? ext_pp : "none";
+ mu_stream_printf(str, "%s/%s%s",
+ SYSCONFDIR, DEFAULT_SCRIPT_FILE_STEM,
+ default_suffixes[0]);
}
#ifdef USE_SYSLOG_ASYNC
# if DEFAULT_SYSLOG_ASYNC == 1
# define DEFAULT_SYSLOG "non-blocking"
# else
@@ -1034,85 +1094,98 @@ string_preprocessor (void)
# define DEFAULT_SYSLOG "blocking"
#endif
enum {
STRING_CONSTANT,
STRING_VARIABLE,
- STRING_FUNCTION
+ STRING_FUNCTION,
+ STRING_PRINTER
};
static struct string_value string_values[] = {
{ "version", STRING_CONSTANT, { .s_const = VERSION } },
- { "script file", STRING_VARIABLE, { .s_var = &script_file } },
- { "preprocessor", STRING_FUNCTION, { .s_func = string_preprocessor } },
- { "user", STRING_VARIABLE, { .s_var = &mf_server_user } },
- { "statedir", STRING_VARIABLE, { .s_var = &mailfromd_state_dir } },
- { "socket", STRING_CONSTANT, { .s_const = DEFAULT_SOCKET } },
- { "pidfile", STRING_VARIABLE, { .s_var = &pidfile } },
- { "default syslog", STRING_CONSTANT, { .s_const = DEFAULT_SYSLOG } },
+ { "script file", STRING_PRINTER, { .s_print = print_script_file } },
+ { "preprocessor", STRING_FUNCTION,
+ { .s_func = string_preprocessor } },
+ { "user", STRING_VARIABLE,
+ { .s_var = &mf_server_user } },
+ { "statedir", STRING_VARIABLE,
+ { .s_var = &mailfromd_state_dir } },
+ { "socket", STRING_CONSTANT,
+ { .s_const = DEFAULT_SOCKET } },
+ { "pidfile", STRING_VARIABLE,
+ { .s_var = &pidfile } },
+ { "default syslog", STRING_CONSTANT,
+ { .s_const = DEFAULT_SYSLOG } },
+ { "include path", STRING_VARIABLE,
+ { .s_var = &include_path.base } },
+ { "module path", STRING_VARIABLE,
+ { .s_var = &module_path.base } },
+#ifdef WITH_MFMOD
+ { "mfmod path", STRING_VARIABLE, { .s_var = &mfmod_path } },
+#endif
+ { "optional features", STRING_PRINTER,
+ { .s_print = print_optional_values } },
+ { "supported database types", STRING_PRINTER,
+ { .s_print = print_supported_dbtypes } },
{ NULL }
};
static void
print_string_values(mu_stream_t str)
{
struct string_value *p;
char const *val;
-
+
for (p = string_values; p->kw; p++) {
set_column(str, keyword_column);
mu_stream_printf(str, "%s:", p->kw);
+ set_column(str, value_column);
switch (p->type) {
case STRING_CONSTANT:
val = p->data.s_const;
break;
case STRING_VARIABLE:
val = *p->data.s_var;
break;
case STRING_FUNCTION:
- val = p->data.s_func ();
+ val = p->data.s_func();
+ break;
+
+ case STRING_PRINTER:
+ p->data.s_print(str);
+ mu_stream_write(str, "\n", 1, NULL);
+ continue;
}
- set_column(str, value_column);
mu_stream_printf(str, "%s\n", val);
}
}
void
mailfromd_show_defaults(void)
{
- int rc;
mu_stream_t str;
-
- rc = mu_wordwrap_stream_create (&str, mu_strout, 0, right_margin);
- if (rc) {
+ struct winsize ws;
+
+ ws.ws_col = ws.ws_row = 0;
+ if ((MAILUTILS_VERSION_MAJOR == 3 && MAILUTILS_VERSION_MINOR < 16) ||
+ ioctl(1, TIOCGWINSZ, (char *) &ws) < 0 || ws.ws_col == 0 ||
+ mu_wordwrap_stream_create (&str, mu_strout, 0, ws.ws_col)) {
str = mu_strout;
mu_stream_ref(str);
}
print_string_values(str);
- list_db_formats(str, "supported databases");
-
- set_column(str, keyword_column);
- mu_stream_printf(str, "%s:", "optional features");
- set_column(str, value_column);
-#if defined WITH_GEOIP
- mu_stream_printf(str, " %s", "GeoIP");
-#endif
-#if defined WITH_DSPAM
- mu_stream_printf(str, " %s", "DSPAM");
-#endif
- mu_stream_write(str, "\n", 1, NULL);
-
db_format_enumerate(db_format_enumerator, str);
- mu_stream_destroy (&str);
+ mu_stream_destroy(&str);
}
static int
args_in_order(int argc, char **argv)
{
int i;
@@ -1188,33 +1261,41 @@ mf_server_function(const char *key, struct mf_srvcfg *cfg)
} else
return 1;
return 0;
}
static void
-open_strecho (int daemon_mode)
+open_strecho(int daemon_mode)
{
int rc;
if (daemon_mode) {
rc = mu_stream_ioctl(mu_strerr, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_CLONE,
&mf_strecho);
if (rc == 0) {
int s = MU_LOG_INFO;
mu_stream_ioctl(mf_strecho, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_SEVERITY,
&s);
+ /* Clear severity suppression, if any */
+ s = MU_LOG_DEBUG;
+ mu_stream_ioctl(mf_strecho, MU_IOCTL_LOGSTREAM,
+ MU_IOCTL_LOGSTREAM_SUPPRESS_SEVERITY,
+ &s);
+ }
+ } else if (echo_output) {
+ if (strcmp(echo_output, "-") == 0) {
+ mf_strecho = mu_strout;
+ mu_stream_ref(mf_strecho);
+ rc = 0;
+ } else {
+ rc = mu_file_stream_create(&mf_strecho, echo_output,
+ MU_STREAM_WRITE|MU_STREAM_CREAT);
}
} else {
-#if 0
- mf_strecho = mu_strout;
- mu_stream_ref(mf_strecho);
- rc = 0;
-#else
rc = mu_stdio_stream_create(&mf_strecho, MU_STDERR_FD, 0);
-#endif
}
if (rc) {
mu_diag_output(MU_LOG_CRIT,
_("cannot create echo output stream: %s"),
mu_strerror(rc));
exit(EX_UNAVAILABLE);
@@ -1234,17 +1315,111 @@ struct mu_cli_setup cli = {
.optv = options,
.cfg = mf_cfg_param,
.prog_doc = prog_doc,
.prog_args = args_doc
};
+/*
+ * Split command line arguments into macro definitions, script file
+ * name and proper arguments, depending on the current mode.
+ *
+ * On input, pargc points to the number of arguments in the command
+ * line and pargv to the vector of arguments. On output, both pargc
+ * and pargv are updated. The script_name is assigned the name of
+ * the MFL script file (or NULL), mc and mv keep number of macro
+ * definitions and vector of these.
+ *
+ * On error, prints a diagnostic message and exits with EX_USAGE
+ * status.
+ */
+static void
+argv_split(int *pargc, char ***pargv, char **script_name,
+ int *mc, char ***mv)
+{
+ int argc = *pargc;
+ char **argv = *pargv;
+ int i, n = -1;
+
+ *script_name = NULL;
+ *mc = 0;
+ *mv = NULL;
+
+ switch (mode) {
+ case MAILFROMD_DAEMON:
+ if (argc == 1) {
+ *script_name = argv[0];
+ argc--;
+ argv++;
+ } else if (argc > 1) {
+ mu_error(_("extra arguments in daemon mode"));
+ exit(EX_USAGE);
+ }
+ break;
+
+ case MAILFROMD_TEST:
+ for (i = 0; i < argc; i++) {
+ if (strchr(argv[i], '=') == 0) {
+ if (n == -1) {
+ n = i;
+ } else {
+ mu_error(_("script file specified "
+ "twice (%s and %s)"),
+ argv[n], argv[i]);
+ exit(EX_USAGE);
+ }
+ }
+ }
+
+ if (n >= 0) {
+ *script_name = argv[n];
+ memmove(argv + n, argv + n + 1,
+ (argc - n + 1) * sizeof argv[0]);
+ argc--;
+ }
+
+ *mc = argc;
+ *mv = argv;
+ argv += argc;
+ argc = 0;
+ break;
+
+ case MAILFROMD_RUN:
+ for (i = 0; i < argc; i++) {
+ if (strchr(argv[i], '=') == 0) {
+ n = i;
+ break;
+ }
+ }
+
+ if (n >= 0) {
+ *script_name = argv[n];
+ argv[n] = NULL;
+ *mc = n;
+ *mv = argv;
+
+ argv += n + 1;
+ argc -= n + 1;
+ }
+ break;
+
+ default:
+ mu_error(_("extra arguments in this mode"));
+ exit(EX_USAGE);
+ }
+
+ *pargc = argc;
+ *pargv = argv;
+}
+
int
main(int argc, char **argv)
{
prog_counter_t entry_point;
int stderr_is_closed = stderr_closed_p();
+ int macc;
+ char **macv;
mf_init_nls();
mf_proctitle_init(argc, argv, environ);
mu_alloc_die_hook = mailfromd_alloc_die;
MU_AUTH_REGISTER_ALL_MODULES();
@@ -1257,32 +1432,33 @@ main(int argc, char **argv)
milter_settimeout(7200);
/* Set default logging */
mu_set_program_name(argv[0]);
mu_log_tag = mu_strdup(mu_program_name);
mu_log_facility = DEFAULT_LOG_FACILITY;
+ mu_log_print_severity = 1;
mu_stdstream_setup(MU_STDSTREAM_RESET_NONE);
mf_srvcfg_log_setup(stderr_is_closed ? "syslog" : "stderr");
debug_init();
libcallout_init();
init_string_space();
init_symbols();
builtin_setup();
mf_runtime_param_finish();
db_format_setup();
- include_path_setup();
pragma_setup();
mf_server_save_cmdline(argc, argv);
dnsbase_init();
mu_acl_cfg_init();
database_cfg_init();
srvman_init();
mf_srvcfg_init(argv[0], "(milter | callout)");
+ preprocessor_cfg_init();
mf_getopt(&cli, &argc, &argv, capa, args_in_order(argc, argv));
if (validate_options())
exit(EX_USAGE);
@@ -1296,44 +1472,28 @@ main(int argc, char **argv)
mu_list_foreach(trace_modules, flush_trace_module, NULL);
mu_list_destroy(&trace_modules);
}
mf_srvcfg_flush();
- alloc_ext_pp();
+ preprocessor_finalize();
if (need_script) {
- char *new_script = NULL;
- if (argc) {
- int i, n = -1;
- for (i = 0; i < argc; i++) {
- if (strchr(argv[i], '=') == 0) {
- if (n == -1) {
- n = i;
- if (mode == MAILFROMD_RUN)
- break;
- } else {
- mu_error(_("script file "
- "specified twice "
- "(%s and %s)"),
- argv[n], argv[i]);
- exit(EX_USAGE);
- }
- }
- }
- if (n >= 0) {
- new_script = argv[n];
- memmove(argv + n, argv + n + 1,
- (argc - n + 1) * sizeof argv[0]);
- argc--;
+ argv_split(&argc, &argv, &script_file, &macc, &macv);
+ if (script_file == NULL) {
+ script_file = path_find_file(SYSCONFDIR,
+ DEFAULT_SCRIPT_FILE_STEM,
+ default_suffixes);
+ if (!script_file) {
+ mu_error(_("filter script file %s/%s%s does not exist or is unreadable"),
+ SYSCONFDIR, DEFAULT_SCRIPT_FILE_STEM,
+ default_suffixes[0]);
+ exit(EX_NOINPUT);
}
}
- if (new_script)
- script_file = new_script;
-
if (script_file[0] != '/')
/* Clear saved command line */
mf_server_save_cmdline(0, NULL);
if (preprocess_option)
exit(preprocess_input());
if (parse_program(script_file, script_ydebug))
@@ -1395,39 +1555,44 @@ main(int argc, char **argv)
mf_namefixup_run(mailfromd_state_dir);
mf_namefixup_free();
switch (mode) {
case MAILFROMD_DAEMON:
- if (argc > 0) {
- mu_error(_("too many arguments"));
- exit(EX_USAGE);
- }
if (script_file[0] != '/') {
mu_diag_output(MU_DIAG_WARNING,
_("script file is given "
"without full file name"));
server_flags |= MF_SERVER_NORESTART;
}
open_strecho(1);
+ /* Startup handlers should be run after assuming user privs. */
+ mf_server_startup_hook = run_startup;
+ mf_server_shutdown_hook = run_shutdown;
mf_server_lint_option = "--lint";
mf_server_start("mailfromd", mailfromd_state_dir, pidfile,
server_flags);
break;
case MAILFROMD_TEST:
+ logger_set_print_severity(0);
open_strecho(0);
- mailfromd_test(argc, argv);
+ run_startup();
+ mailfromd_test(macc, macv);
+ run_shutdown();
break;
case MAILFROMD_SHOW_DEFAULTS:
mailfromd_show_defaults();
break;
case MAILFROMD_RUN:
+ logger_set_print_severity(0);
open_strecho(0);
- mailfromd_run(entry_point, argc, argv);
+ run_startup();
+ mailfromd_run(entry_point, argc, argv, macc, macv);
+ run_shutdown();
}
exit(EX_OK);
}

Return to:

Send suggestions and report system problems to the System administrator.