aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2008-11-13 19:02:54 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2008-11-13 19:02:54 +0000
commit20bec15fe6bc356b8ed3e8ee8469b5f10f34b04b (patch)
treedbe37e84739cbdd57c7ffc6cb4c59ea6d2f6830e
parent2f82db82c0a25c310ef25d0ea761a97e706293ea (diff)
downloadpies-20bec15fe6bc356b8ed3e8ee8469b5f10f34b04b.tar.gz
pies-20bec15fe6bc356b8ed3e8ee8469b5f10f34b04b.tar.bz2
Implement file output redirection.
* pies/pies.h (enum retr_type): New constants. (struct retranslator): New type. (struct component): Change type of retr to struct retranslator. All uses updated. * pies/pies.c (_cb_retr): Takes two arguments: redirection type and file name or syslog priority. (make_full_name): New function. (component_verify): Check retr file names. * pies/progman.c (redirect_to_file): New function. (open_retranslator): Handle file redirects. (prog_start): Open /dev/null in wronly mode. * pies/meta1gram.y (create_retr_node): New function. (translate_node_list): Create default "stderr" statement.
-rwxr-xr-xbootstrap3
-rw-r--r--pies/meta1gram.y39
-rw-r--r--pies/pies.c169
-rw-r--r--pies/pies.h25
-rw-r--r--pies/progman.c55
5 files changed, 231 insertions, 60 deletions
diff --git a/bootstrap b/bootstrap
index 0fa016d..a93ee90 100755
--- a/bootstrap
+++ b/bootstrap
@@ -557,15 +557,16 @@ fi
# unusual case in which a symlinked-to .m4 file is git-removed from gnulib
# between successive runs of this script.
find "$m4_base" -name '*.m4' -depth -type l -xtype l -delete > /dev/null 2>&1
# Reconfigure, getting other files.
+aclocal_flags=`sed -n 's/ACLOCAL_AMFLAGS *=//p' Makefile.am`
for command in \
libtool \
- 'aclocal --force -I m4' \
+ "aclocal --force $aclocal_flags" \
'autoconf --force' \
'autoheader --force' \
'automake --add-missing --copy --force-missing';
do
if test "$command" = libtool; then
grep '^[ ]*AM_PROG_LIBTOOL\>' configure.ac >/dev/null ||
diff --git a/pies/meta1gram.y b/pies/meta1gram.y
index ac72d16..91bcb6d 100644
--- a/pies/meta1gram.y
+++ b/pies/meta1gram.y
@@ -330,12 +330,34 @@ create_string_node (const char *tag, const char *str, mu_cfg_locus_t *locus)
val->v.string = meta1_string (str, strlen (str));
return alloc_node (mu_cfg_node_param, locus, tag, val, NULL);
}
static mu_cfg_node_t *
+create_retr_node (const char *tag, const char *dir,
+ const char *name, mu_cfg_locus_t *locus)
+{
+ mu_config_value_t *val = create_value (MU_CFG_ARRAY);
+ val->v.arg.c = 2;
+ val->v.arg.v = mu_alloc (2 * sizeof (val->v.arg.v[0]));
+
+ val->v.arg.v[1].type = MU_CFG_STRING;
+ val->v.arg.v[0].v.string = meta1_string ("file", 4);
+
+ val->v.arg.v[1].type = MU_CFG_STRING;
+ meta1_line_begin ();
+ meta1_line_add (dir, strlen (dir));
+ meta1_line_add ("/", 1);
+ meta1_line_add (name, strlen (name));
+ meta1_line_add (".log", 4);
+ val->v.arg.v[1].v.string = meta1_line_finish ();
+
+ return alloc_node (mu_cfg_node_param, locus, tag, val, NULL);
+}
+
+static mu_cfg_node_t *
translate_node (mu_cfg_node_t *src)
{
mu_cfg_node_t *dst = NULL;
struct node_trans *nt = find_node_trans (root_node_trans, src->tag);
if (nt)
@@ -347,14 +369,17 @@ translate_node (mu_cfg_node_t *src)
nt->new_name, config_value_dup (src->label),
NULL);
}
return dst;
}
+#define META1_QUEUE_DIR() \
+ (meta1_queue_dir ? meta1_queue_dir : "/var/spool/meta1")
+
static mu_cfg_node_t *
-translate_node_list (mu_cfg_node_t *src)
+translate_node_list (mu_cfg_node_t *src, const char *name)
{
mu_cfg_node_t *head = NULL, *tail = NULL;
mu_cfg_locus_t *locus = &src->locus;
for (; src; src = src->next)
{
@@ -374,18 +399,20 @@ translate_node_list (mu_cfg_node_t *src)
mu_cfg_node_t *node;
node = create_string_node ("allgroups", "yes", locus);
tail->next = node;
tail = node;
- node = create_string_node ("chdir",
- meta1_queue_dir ?
- meta1_queue_dir : "/var/spool/meta1",
- locus);
+ node = create_string_node ("chdir", META1_QUEUE_DIR (), locus);
+ tail->next = node;
+ tail = node;
+
+ node = create_retr_node ("stderr", META1_QUEUE_DIR (), name, locus);
tail->next = node;
tail = node;
+
}
return head;
}
static mu_cfg_node_t *
translate_component (mu_cfg_node_t *src)
@@ -394,11 +421,11 @@ translate_component (mu_cfg_node_t *src)
if (src->type == mu_cfg_node_tag)
{
mu_config_value_t *val = create_value (MU_CFG_STRING);
val->v.string = meta1_string (src->tag, strlen (src->tag));
dst = alloc_node (mu_cfg_node_tag, &src->locus,
"component", val,
- translate_node_list (src->node));
+ translate_node_list (src->node, val->v.string));
}
return dst;
}
diff --git a/pies/pies.c b/pies/pies.c
index 46df904..7f1ed35 100644
--- a/pies/pies.c
+++ b/pies/pies.c
@@ -458,21 +458,89 @@ _cb_facility (mu_debug_t debug, void *data, mu_config_value_t *val)
return 0;
}
static int
_cb_retr (mu_debug_t debug, void *data, mu_config_value_t *arg)
{
- if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug))
- return 1;
- if (mu_string_to_syslog_priority (arg->v.string, data))
+ struct retranslator *rp = data;
+ static struct mu_kwd retrtab[] = {
+ { "null", retr_null },
+ { "syslog", retr_syslog },
+ { "file", retr_file },
+ { NULL }
+ };
+ int res;
+
+ switch (arg->type)
{
- mu_cfg_format_error (debug, MU_DEBUG_ERROR,
- _("Unknown syslog priority `%s'"),
- arg);
- return 1;
+ case MU_CFG_STRING:
+ if (strcmp (arg->v.string, "null") == 0)
+ {
+ rp->type = retr_null;
+ break;
+ }
+ rp->type = retr_syslog;
+ if (mu_string_to_syslog_priority (arg->v.string, &rp->v.prio))
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("Unknown syslog priority `%s'"),
+ arg);
+ return 0;
+ }
+ break;
+
+ case MU_CFG_ARRAY:
+ if (mu_cfg_assert_value_type (&arg->v.arg.v[0], MU_CFG_STRING, debug))
+ return 0;
+ if (mu_kwd_xlat_name (retrtab, arg->v.arg.v[0].v.string, &res))
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("%s: unrecognised retranslator type"),
+ arg->v.arg.v[0].v.string);
+ else
+ {
+ if (res != retr_null)
+ {
+ if (arg->v.arg.c != 2)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("wrong number of arguments"));
+ return 0;
+ }
+ if (mu_cfg_assert_value_type (&arg->v.arg.v[1], MU_CFG_STRING,
+ debug))
+ return 0;
+
+ switch (res)
+ {
+ case retr_null:
+ break;
+
+ case retr_syslog:
+ if (mu_string_to_syslog_priority (arg->v.arg.v[1].v.string,
+ &rp->v.prio))
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("Unknown syslog priority `%s'"),
+ arg->v.arg.v[1].v.string);
+ return 0;
+ }
+ break;
+
+ case retr_file:
+ rp->v.file = xstrdup (arg->v.arg.v[1].v.string);
+ break;
+ }
+ }
+ rp->type = res;
+ }
+ break;
+
+ default:
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR, _("unexpected list"));
}
+
return 0;
}
static int
_cb_url (mu_debug_t debug, void *data, mu_config_value_t *arg)
{
@@ -591,23 +659,23 @@ struct mu_cfg_param component_cfg_param[] = {
{ "facility", mu_cfg_callback, NULL,
mu_offsetof (struct component, facility), _cb_facility,
N_("Override default facility for this component."),
N_("arg") },
{ "stdout", mu_cfg_callback, NULL,
mu_offsetof (struct component, retr[RETR_OUT]), _cb_retr,
- N_("Redirect program's standard output to the given syslog priority."),
- /* TRANSLATORS: The words between '{' and '}' are keywords, do not
- translate them. */
- N_("prio: {emerg | alert | crit | err | warning | notice | info | debug}")
+ N_("Redirect program's standard output to the given file or "
+ "syslog priority."),
+ /* TRANSLATORS: file and syslog are keywords. Do not translate them. */
+ N_("type: {file | syslog}> <channel: string")
},
{ "stderr", mu_cfg_callback, NULL,
mu_offsetof (struct component, retr[RETR_ERR]), _cb_retr,
- N_("Redirect program's standard error to the given syslog priority."),
- /* TRANSLATORS: The words between '{' and '}' are keywords, do not
- translate them. */
- N_("prio: {emerg | alert | crit | err | warning | notice | info | debug}")
+ N_("Redirect program's standard error to the given file or "
+ "syslog priority."),
+ /* TRANSLATORS: file and syslog are keywords. Do not translate them. */
+ N_("type: {file | syslog}> <channel: string")
},
{ "user", mu_cfg_string, NULL,
mu_offsetof (struct component, privs.user), NULL,
N_("Run with this user privileges.") },
{ "group", mu_cfg_callback, NULL,
mu_offsetof (struct component, privs.groups), _cb_group,
@@ -632,80 +700,107 @@ struct mu_cfg_param component_cfg_param[] = {
N_("Change to this directory before executing the component."),
N_("dir") },
{ "return-code", mu_cfg_section },
{ NULL }
};
+static char *
+make_full_name (const char *dir, const char *file)
+{
+ char *p;
+ size_t len = strlen (dir);
+
+ while (len > 0 && dir[len-1] == '/')
+ len--;
+ p = xmalloc (len + 1 + strlen (file) + 1);
+ memcpy (p, dir, len);
+ p[len++] = '/';
+ strcpy (p + len, file);
+ return p;
+}
+
static int
component_verify (struct component *comp, mu_debug_t debug)
{
int header = 0;
-#define COMPERR(s) \
+ int i;
+#define COMPERR(fmt, arg) \
do \
{ \
if (!header) \
{ \
mu_cfg_format_error (debug, MU_DEBUG_ERROR, \
_("in component %s:"), comp->tag); \
header = 1; \
} \
- mu_cfg_format_error (debug, MU_DEBUG_ERROR, "%s", s); \
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR, fmt, arg); \
} \
while (0)
if (!comp->argv)
- COMPERR (_("missing command line"));
+ COMPERR ("%s", _("missing command line"));
if (comp->pass_fd_socket && comp->mode != pies_comp_pass_fd)
- COMPERR (_("pass-fd-socket ignored: wrong mode"));
+ COMPERR ("%s", _("pass-fd-socket ignored: wrong mode"));
switch (comp->mode)
{
case pies_comp_exec:
if (comp->socket_url)
- COMPERR (_("socket ignored: wrong mode"));
+ COMPERR ("%s", _("socket ignored: wrong mode"));
break;
case pies_comp_pass_fd:
if (!comp->pass_fd_socket)
- COMPERR (_("must supply pass-fd-socket in this mode"));
+ COMPERR ("%s", _("must supply pass-fd-socket in this mode"));
else if (comp->pass_fd_socket[0] != '/')
{
if (comp->dir)
{
- char *p;
- size_t len = strlen (comp->dir);
-
- while (len > 0 && comp->dir[len-1] == '/')
- len--;
- p = xmalloc (len + 1 + strlen (comp->pass_fd_socket) + 1);
- memcpy (p, comp->dir, len);
- p[len++] = '/';
- strcpy (p + len, comp->pass_fd_socket);
+ char *p = make_full_name (comp->dir, comp->pass_fd_socket);
free (comp->pass_fd_socket);
comp->pass_fd_socket = p;
}
else
- COMPERR (_("pass-fd-socket must be an absolute "
- "file name or chdir must be specified"));
+ COMPERR ("%s", _("pass-fd-socket must be an absolute "
+ "file name or chdir must be specified"));
}
/* Fall through */
case pies_comp_accept:
case pies_comp_inetd:
if (!comp->socket_url)
{
- COMPERR (_("socket must be specified in this mode"));
+ COMPERR ("%s", _("socket must be specified in this mode"));
/* FIXME: Memory leak */
return 1;
}
}
- if (comp->mode != pies_comp_exec && comp->retr[RETR_OUT] != -1)
+ if (comp->mode != pies_comp_exec
+ && comp->retr[RETR_OUT].type != retr_null)
+ {
+ COMPERR ("%s", _("stdout retranslation invalid in this mode"));
+ comp->retr[RETR_OUT].type = retr_null;
+ }
+
+ for (i = RETR_OUT; i <= RETR_ERR; i++)
{
- COMPERR (_("stdout retranslation invalid in this mode"));
- comp->retr[RETR_OUT] = -1;
+ if (comp->retr[i].type == retr_file && comp->retr[i].v.file[0] != '/')
+ {
+ if (comp->dir)
+ {
+ char *p = make_full_name (comp->dir, comp->retr[i].v.file);
+ free (comp->retr[i].v.file);
+ comp->retr[i].v.file = p;
+ }
+ else
+ COMPERR (_("%s: must be an absolute "
+ "file name or chdir must be specified"),
+ comp->retr[i].v.file);
+ }
}
+
return header;
#undef COMPERR
}
static int
component_section_parser (enum mu_cfg_section_stage stage,
@@ -725,13 +820,13 @@ component_section_parser (enum mu_cfg_section_stage stage,
return 1;
comp = progman_lookup_component (node->label->v.string);
if (!comp)
{
comp = xzalloc (sizeof (*comp));
comp->facility = mu_log_facility;
- comp->retr[RETR_OUT] = comp->retr[RETR_ERR] = -1;
+ comp->retr[RETR_OUT].type = comp->retr[RETR_ERR].type = retr_null;
comp->tag = node->label ? xstrdup (node->label->v.string) : NULL;
}
*section_data = comp;
break;
case mu_cfg_section_end:
diff --git a/pies/pies.h b/pies/pies.h
index 3806f61..806c82f 100644
--- a/pies/pies.h
+++ b/pies/pies.h
@@ -44,19 +44,36 @@
#include "inttostr.h"
#include "xalloc.h"
#include "c-ctype.h"
#include "libmf.h"
-#define RETR_OUT 0
-#define RETR_ERR 1
-
#define TESTTIME 2*60
#define SLEEPTIME 5*60
#define MAXSPAWN 10
+#define RETR_OUT 0
+#define RETR_ERR 1
+
+enum retr_type
+{
+ retr_null,
+ retr_syslog,
+ retr_file
+};
+
+struct retranslator
+{
+ enum retr_type type;
+ union
+ {
+ int prio;
+ char *file;
+ } v;
+};
+
typedef struct limits_rec *limits_record_t;
struct pies_privs_data
{
char *user;
mu_list_t groups;
@@ -118,13 +135,13 @@ struct component
mu_url_t socket_url; /* Socket to listen on (if mode != pies_comp_exec) */
char *pass_fd_socket; /* Socket to pass fd on
(if mode == pies_comp_pass_fd) */
mu_acl_t acl;
/* Retranslators: */
int facility; /* Syslog facility. */
- int retr[2]; /* Priorities for stdout and stderr */
+ struct retranslator retr[2]; /* Retranslators for stdout and stderr */
/* Actions to execute on various exit codes: */
struct action *act[MAX_RETURN_CODE+1];
};
extern char *syslog_tag;
extern unsigned long shutdown_timeout;
diff --git a/pies/progman.c b/pies/progman.c
index 4fa6c81..215500d 100644
--- a/pies/progman.c
+++ b/pies/progman.c
@@ -210,15 +210,15 @@ progman_register_retranslators ()
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
if (IS_PROG (prog))
{
struct component *comp = prog->v.p.comp;
- if (comp->retr[RETR_OUT] != -1)
+ if (comp->retr[RETR_OUT].type != retr_null)
register_retr (RETR_OUT, prog);
- if (comp->retr[RETR_ERR] != -1)
+ if (comp->retr[RETR_ERR].type != retr_null)
register_retr (RETR_ERR, prog);
}
}
static struct prog *
register_prog0 (struct component *comp)
@@ -243,13 +243,13 @@ register_prog0 (struct component *comp)
newp->v.p.status = status_listener;
for (i = 0; i <= MAX_RETURN_CODE; i++)
if (!comp->act[i])
comp->act[i] = default_component.act[i];
if (comp->mode != pies_comp_exec)
- comp->retr[RETR_OUT] = -1;
+ comp->retr[RETR_OUT].type = retr_null;
link_prog (newp, 0);
return newp;
}
void
@@ -345,30 +345,60 @@ RETSIGTYPE
retr_exit (int sig)
{
_exit (0);
}
int
-open_retranslator (struct prog *master, int type)
+redirect_to_file (struct prog *master, int stream)
+{
+ struct passwd *pw;
+ int fd = open (master->v.p.comp->retr[stream].v.file, O_RDWR|O_CREAT,
+ 0644 & ~master->v.p.comp->umask);
+ if (fd == -1)
+ {
+ mu_error (_("cannot open output file %s: %s"),
+ master->v.p.comp->retr[stream].v.file,
+ mu_strerror (errno));
+ return -1;
+ }
+ /* Fix file ownership */
+ pw = getpwnam (master->v.p.comp->privs.user);
+ if (pw)
+ chown (master->v.p.comp->retr[stream].v.file, pw->pw_uid, pw->pw_gid);
+ return fd;
+}
+
+int
+open_retranslator (struct prog *master, int stream)
{
int p[2];
FILE *fp;
char *buf = NULL;
size_t size = 0;
pid_t pid;
- int i;
+ int i, prio;
char *tag;
- if (master->v.p.comp->retr[type] == -1)
- return -1;
+ switch (master->v.p.comp->retr[stream].type)
+ {
+ case retr_null:
+ return -1;
+
+ case retr_file:
+ return redirect_to_file (master, stream);
+
+ case retr_syslog:
+ break;
+ }
+
pipe (p);
switch (pid = fork ())
{
case 0:
/* Retranslator process */
- tag = retr_tag (master->tag, type);
+ tag = retr_tag (master->tag, stream);
mf_proctitle_format ("pies: %s retranslator", tag);
free (tag);
for (i = getmaxfd (); i >= 0; i--)
{
if (i != p[0])
@@ -380,24 +410,25 @@ open_retranslator (struct prog *master, int type)
close (p[1]);
fp = fdopen (p[0], "r");
if (fp == NULL)
exit (1);
openlog (master->tag, LOG_PID, master->facility);
+ prio = master->v.p.comp->retr[stream].v.prio;
while (getline (&buf, &size, fp) > 0)
- syslog (master->v.p.comp->retr[type], "%s", buf);
+ syslog (prio, "%s", buf);
exit (0);
case -1:
mu_diag_output (MU_DIAG_CRIT,
_("cannot run retranslator `%s': fork failed: %s"),
master->tag, mu_strerror (errno));
return -1;
default:
- update_retr (type, master, pid);
+ update_retr (stream, master, pid);
close (p[0]);
return p[1];
}
}
extern char **environ;
@@ -684,13 +715,13 @@ prog_start (struct prog *prog)
{
case pies_comp_pass_fd:
case pies_comp_exec:
if (retr[RETR_OUT] == -1)
{
close (1);
- open ("/dev/null", O_RDWR);
+ open ("/dev/null", O_WRONLY);
}
else if (retr[RETR_OUT] != 1)
{
dup2 (retr[RETR_OUT], 1);
}
break;
@@ -704,13 +735,13 @@ prog_start (struct prog *prog)
break;
}
if (retr[RETR_ERR] == -1)
{
close (2);
- open ("/dev/null", O_RDWR);
+ open ("/dev/null", O_WRONLY);
}
else if (retr[RETR_ERR] != 1)
{
dup2 (retr[RETR_ERR], 2);
}

Return to:

Send suggestions and report system problems to the System administrator.