From 20bec15fe6bc356b8ed3e8ee8469b5f10f34b04b Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 13 Nov 2008 19:02:54 +0000 Subject: 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. --- bootstrap | 3 +- pies/meta1gram.y | 39 +++++++++++-- pies/pies.c | 169 +++++++++++++++++++++++++++++++++++++++++++------------ pies/pies.h | 25 ++++++-- pies/progman.c | 55 ++++++++++++++---- 5 files changed, 231 insertions(+), 60 deletions(-) diff --git a/bootstrap b/bootstrap index 0fa016d..a93ee90 100755 --- a/bootstrap +++ b/bootstrap @@ -560,9 +560,10 @@ 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'; diff --git a/pies/meta1gram.y b/pies/meta1gram.y index ac72d16..91bcb6d 100644 --- a/pies/meta1gram.y +++ b/pies/meta1gram.y @@ -332,6 +332,28 @@ create_string_node (const char *tag, const char *str, mu_cfg_locus_t *locus) 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) { @@ -350,8 +372,11 @@ translate_node (mu_cfg_node_t *src) 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; @@ -377,12 +402,14 @@ translate_node_list (mu_cfg_node_t *src) 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; } @@ -397,7 +424,7 @@ translate_component (mu_cfg_node_t *src) 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 @@ -461,15 +461,83 @@ _cb_facility (mu_debug_t debug, void *data, mu_config_value_t *val) 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; } @@ -594,17 +662,17 @@ struct mu_cfg_param component_cfg_param[] = { 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}> 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) \ @@ -648,43 +732,35 @@ component_verify (struct component *comp, mu_debug_t debug) _("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 */ @@ -692,17 +768,36 @@ component_verify (struct component *comp, mu_debug_t debug) 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 } @@ -728,7 +823,7 @@ component_section_parser (enum mu_cfg_section_stage stage, { 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; diff --git a/pies/pies.h b/pies/pies.h index 3806f61..806c82f 100644 --- a/pies/pies.h +++ b/pies/pies.h @@ -47,13 +47,30 @@ #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 @@ -121,7 +138,7 @@ struct component 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]; }; diff --git a/pies/progman.c b/pies/progman.c index 4fa6c81..215500d 100644 --- a/pies/progman.c +++ b/pies/progman.c @@ -213,9 +213,9 @@ progman_register_retranslators () 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); } } @@ -246,7 +246,7 @@ register_prog0 (struct component *comp) 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; @@ -348,24 +348,54 @@ retr_exit (int sig) } 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); @@ -383,8 +413,9 @@ open_retranslator (struct prog *master, int type) 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: @@ -394,7 +425,7 @@ open_retranslator (struct prog *master, int type) return -1; default: - update_retr (type, master, pid); + update_retr (stream, master, pid); close (p[0]); return p[1]; } @@ -687,7 +718,7 @@ prog_start (struct prog *prog) if (retr[RETR_OUT] == -1) { close (1); - open ("/dev/null", O_RDWR); + open ("/dev/null", O_WRONLY); } else if (retr[RETR_OUT] != 1) { @@ -707,7 +738,7 @@ prog_start (struct prog *prog) if (retr[RETR_ERR] == -1) { close (2); - open ("/dev/null", O_RDWR); + open ("/dev/null", O_WRONLY); } else if (retr[RETR_ERR] != 1) { -- cgit v1.2.1