/* This file is part of Mailfromd.
Copyright (C) 2008 Sergey Poznyakoff
This program 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,
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/>. */
#include "pies.h"
#include "meta1lex.h"
int log_to_stderr; /* Use stderr for logging */
char *log_tag; /* override mu_log_tag */
mu_log_level_t debug_level;
mu_debug_t pies_debug;
struct mf_privs pies_privs;
int foreground;
int command;
char *pidfile = STATEDIR "/pies.pid";
char *ctlfile = STATEDIR "/pies.ctl";
char *statfile = STATEDIR "/pies.stat";
mode_t pies_umask = 0;
unsigned long shutdown_timeout = 5;
mu_acl_t pies_acl;
limits_record_t pies_limits;
int force_option;
/* Logging */
void
log_setup (int want_stderr)
{
mu_debug_t debug;
mu_diag_get_debug (&debug);
if (log_tag)
mu_log_tag = log_tag;
if (!want_stderr)
{
openlog (MU_LOG_TAG (), LOG_PID, mu_log_facility);
mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
mu_debug_default_printer = mu_debug_syslog_printer;
}
else
mu_debug_default_printer = mu_debug_stderr_printer;
}
static int
stderr_closed_p()
{
int fd = dup (0);
if (fd < 0)
return 1;
close (fd);
return fd <= 2;
}
static int
_cb_action (mu_debug_t debug, void *data, mu_config_value_t *arg)
{
enum return_action *pact = data;
static struct mu_kwd actab[] = {
{ "disable", action_disable },
{ "restart", action_restart },
{ NULL }
};
int res;
if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug))
return 1;
if (mu_kwd_xlat_name (actab, arg->v.string, &res))
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("unknown action code: %s"), arg);
return 0;
}
*pact = res;
return 0;
}
static int
_cb_notify_addr (mu_debug_t debug, void *data, mu_config_value_t *arg)
{
mu_address_t *paddr = data;
mu_address_t addr;
int rc;
if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug))
return 1;
rc = mu_address_create (&addr, arg->v.string);
if (rc)
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("%s: invalid e-mail address: %s"),
arg->v.string, mu_strerror (rc));
if (*paddr)
{
mu_address_union (paddr, addr);
mu_address_destroy (&addr);
}
else
*paddr = addr;
return 0;
}
struct mu_cfg_param return_code_cfg_param[] = {
{ "action", mu_cfg_callback, NULL,
mu_offsetof (struct action, act), _cb_action,
N_("Specifies action to take when a component finishes with this "
"return code."),
/* TRANSLATORS: disable and restart are keywords, do not translate them. */
N_("arg: {disable | restart}") },
{ "notify", mu_cfg_callback, NULL,
mu_offsetof (struct action, addr), _cb_notify_addr,
N_("Notify this address when then component terminates."),
N_("arg: email-list") },
{ "message", mu_cfg_string, NULL,
mu_offsetof (struct action, message), NULL,
N_("Notification message text (with headers).") },
{ NULL }
};
static struct mu_kwd ex_kwtab[] = {
#define S(s) { #s, s }
S (EX_OK),
S (EX_USAGE),
S (EX_DATAERR),
S (EX_NOINPUT),
S (EX_NOUSER),
S (EX_NOHOST),
S (EX_UNAVAILABLE),
S (EX_SOFTWARE),
S (EX_OSERR),
S (EX_OSFILE),
S (EX_CANTCREAT),
S (EX_IOERR),
S (EX_TEMPFAIL),
S (EX_PROTOCOL),
S (EX_NOPERM),
S (EX_CONFIG),
{ NULL }
};
static struct action *
create_action(struct component *comp,
mu_debug_t debug, mu_config_value_t *val, int argc,
const char *(*getarg) (mu_config_value_t *, int, mu_debug_t))
{
int i;
int *retv;
int retc = 0;
int allflag = 0;
struct action *act;
retv = xcalloc (argc, sizeof *retv);
if (argc == 0 || (argc == 1 && strcmp (getarg(val, 0, debug), "*") == 0))
allflag = 1;
else
{
for (i = 0; i < argc; i++)
{
int n;
const char *arg = getarg(val, i, debug);
if (isdigit (arg[0]))
{
char *p;
n = strtoul (arg, &p, 0);
if (*p)
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("%s: not a number"), p);
continue;
}
}
else if (mu_kwd_xlat_name_ci (ex_kwtab, arg, &n))
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("%s: not a return code"), arg);
continue;
}
if (n > MAX_RETURN_CODE)
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("%s: invalid return code"), arg);
else
{
/* Alles in ordnung */
retv[retc++] = n;
}
}
}
if (retc == 0 && !allflag)
{
free (retv);
return NULL;
}
act = xzalloc (sizeof *act);
if (allflag)
{
for (i = 0; i <= MAX_RETURN_CODE; i++)
if (comp->act[i] == NULL)
comp->act[i] = act;
}
else
for (i = 0; i < retc; i++)
comp->act[retv[i]] = act;
free (retv);
return act;
}
const char *
_get_string_arg (mu_config_value_t *val, int num, mu_debug_t debug)
{
if (num != 0)
return NULL;
return val->v.string;
}
const char *
_get_array_arg (mu_config_value_t *val, int num, mu_debug_t debug)
{
if (num < val->v.arg.c)
{
if (mu_cfg_assert_value_type (&val->v.arg.v[num], MU_CFG_STRING,
debug) == 0)
return val->v.arg.v[num].v.string;
}
return NULL;
}
const char *
_get_list_arg (mu_config_value_t *val, int num, mu_debug_t debug)
{
mu_config_value_t *elt;
int rc = mu_list_get (val->v.list, num, (void**)&elt);
if (rc)
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("cannot get list item: %s"),
mu_strerror (rc));
}
else if (mu_cfg_assert_value_type (elt, MU_CFG_STRING, debug) == 0)
return elt->v.string;
return NULL;
}
static int
return_code_section_parser (enum mu_cfg_section_stage stage,
const mu_cfg_node_t *node,
const char *section_label, void **section_data,
void *call_data,
mu_cfg_tree_t *tree)
{
struct component *comp = *section_data;
size_t count;
struct action *act;
switch (stage)
{
case mu_cfg_section_start:
switch (node->label->type)
{
case MU_CFG_STRING:
act = create_action(comp, tree->debug, node->label,
1,
_get_string_arg);
break;
case MU_CFG_ARRAY:
act = create_action(comp, tree->debug, node->label,
node->label->v.arg.c,
_get_array_arg);
break;
case MU_CFG_LIST:
mu_list_count (node->label->v.list, &count);
act = create_action(comp, tree->debug, node->label,
count,
_get_list_arg);
}
if (!act)
return 1;
*section_data = act;
break;
case mu_cfg_section_end:
break;
}
return 0;
}
void
return_code_cfg_init ()
{
struct mu_cfg_section *section;
if (mu_create_canned_section ("return-code", §ion))
exit (EX_SOFTWARE);
section->parser = return_code_section_parser;
section->label = N_("<tag: exit-code-list>");
mu_cfg_section_add_params (section, return_code_cfg_param);
}
static int
_cb_command (mu_debug_t debug, void *data, mu_config_value_t *val)
{
int argc;
char **argv, ***pargv = data;
int rc;
switch (val->type)
{
case MU_CFG_STRING:
rc = mu_argcv_get (val->v.string, "", NULL, &argc, &argv);
if (rc)
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
"mu_argcv_get: %s", mu_strerror (rc));
return 1;
}
break;
case MU_CFG_ARRAY:
argv = config_array_to_argv (val, debug);
break;
case MU_CFG_LIST:
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("unexpected list"));
return 1;
}
*pargv = argv;
return 0;
}
static int
_cb_umask (mu_debug_t debug, void *data, mu_config_value_t *arg)
{
mode_t *pmode = data;
char *p;
unsigned long n;
if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug))
return 1;
n = strtoul (arg->v.string, &p, 8);
if (*p)
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
_("Invalid octal number"));
return 1;
}
*pmode = n;
return 0;
}
static int
_cb_env (mu_debug_t debug, void *data, mu_config_value_t *val)
{
int rc;
int argc;
char **argv;
char ***penv = data;
switch (val->type)
{
case MU_CFG_STRING:
rc = mu_argcv_get_np (val->v.string,
|