aboutsummaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c401
1 files changed, 283 insertions, 118 deletions
diff --git a/src/main.c b/src/main.c
index 7fe40dbc..64c50468 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,18 +1,18 @@
/* 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>
@@ -31,6 +31,8 @@
#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>
@@ -53,7 +55,7 @@ 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 */
@@ -64,7 +66,6 @@ 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;
@@ -76,6 +77,7 @@ 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)
@@ -334,10 +336,9 @@ opt_daemon(struct mu_parseopt *po, struct mu_option *op,
}
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
@@ -407,23 +408,45 @@ opt_relayed_domain_file(struct mu_parseopt *po, struct mu_option *op,
}
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)
+{
+ preprocessor.enabled = 0;
+}
+
+static void
+opt_preprocessor(struct mu_parseopt *po, struct mu_option *op, char const *arg)
{
- ext_pp = NULL;
+ 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)
{
+ 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)
{
+ 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
@@ -555,10 +578,14 @@ static struct mu_option mailfromd_options[] = {
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 },
@@ -581,14 +608,17 @@ static struct mu_option mailfromd_options[] = {
{ "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 },
@@ -735,25 +765,15 @@ cb_set_variable(void *data, mu_config_value_t *arg)
}
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:
@@ -761,7 +781,7 @@ cb_include_path(void *data, mu_config_value_t *val)
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;
@@ -774,7 +794,7 @@ cb_include_path(void *data, mu_config_value_t *val)
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);
}
@@ -808,6 +828,15 @@ cb_trace_program(void *data, mu_config_value_t *val)
}
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) {
@@ -816,7 +845,7 @@ cb_relayed_domain_file(void *data, mu_config_value_t *val)
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:
@@ -828,6 +857,7 @@ cb_relayed_domain_file(void *data, mu_config_value_t *val)
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.") },
@@ -837,11 +867,16 @@ struct mu_cfg_param mf_cfg_param[] = {
{ "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") },
@@ -859,16 +894,7 @@ struct mu_cfg_param mf_cfg_param[] = {
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 }
@@ -926,7 +952,6 @@ mf_runtime_param_finish()
}
-
/* Auxiliary functions */
unsigned keyword_column = 0;
unsigned header_column = 2;
@@ -970,17 +995,12 @@ db_format_enumerator(struct db_format *fmt, void *data)
}
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"));
@@ -1001,11 +1021,11 @@ list_db_formats(mu_stream_t str, const char *pfx)
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 {
@@ -1014,14 +1034,54 @@ struct string_value {
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 *
+char const *
string_preprocessor(void)
{
- return ext_pp ? ext_pp : "none";
+ 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)
+{
+ mu_stream_printf(str, "%s/%s%s",
+ SYSCONFDIR, DEFAULT_SCRIPT_FILE_STEM,
+ default_suffixes[0]);
}
#ifdef USE_SYSLOG_ASYNC
@@ -1037,18 +1097,36 @@ string_preprocessor (void)
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 }
};
@@ -1061,6 +1139,7 @@ print_string_values(mu_stream_t str)
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:
@@ -1073,9 +1152,14 @@ print_string_values(mu_stream_t str)
case STRING_FUNCTION:
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);
}
}
@@ -1083,30 +1167,19 @@ print_string_values(mu_stream_t str)
void
mailfromd_show_defaults(void)
{
- int rc;
mu_stream_t str;
+ struct winsize ws;
- rc = mu_wordwrap_stream_create (&str, mu_strout, 0, right_margin);
- if (rc) {
+ 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);
@@ -1203,15 +1276,23 @@ open_strecho (int daemon_mode)
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 0
+ } else if (echo_output) {
+ if (strcmp(echo_output, "-") == 0) {
mf_strecho = mu_strout;
mu_stream_ref(mf_strecho);
rc = 0;
-#else
+ } else {
+ rc = mu_file_stream_create(&mf_strecho, echo_output,
+ MU_STREAM_WRITE|MU_STREAM_CREAT);
+ }
+ } else {
rc = mu_stdio_stream_create(&mf_strecho, MU_STDERR_FD, 0);
-#endif
}
if (rc) {
mu_diag_output(MU_LOG_CRIT,
@@ -1237,11 +1318,105 @@ struct mu_cli_setup cli = {
.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);
@@ -1260,6 +1435,7 @@ main(int argc, char **argv)
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");
@@ -1270,7 +1446,6 @@ main(int argc, char **argv)
builtin_setup();
mf_runtime_param_finish();
db_format_setup();
- include_path_setup();
pragma_setup();
mf_server_save_cmdline(argc, argv);
@@ -1280,6 +1455,7 @@ main(int argc, char **argv)
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));
@@ -1299,38 +1475,22 @@ main(int argc, char **argv)
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);
@@ -1398,10 +1558,6 @@ main(int argc, char **argv)
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 "
@@ -1409,14 +1565,20 @@ main(int argc, char **argv)
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:
@@ -1424,8 +1586,11 @@ main(int argc, char **argv)
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.