diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.gitignore | 6 | ||||
-rw-r--r-- | src/Makefile.am | 57 | ||||
-rw-r--r-- | src/depmap.c | 170 | ||||
-rw-r--r-- | src/limits.c | 299 | ||||
-rw-r--r-- | src/meta1gram.y | 439 | ||||
-rw-r--r-- | src/meta1lex.h | 31 | ||||
-rw-r--r-- | src/meta1lex.l | 231 | ||||
-rw-r--r-- | src/pies.c | 1581 | ||||
-rw-r--r-- | src/pies.h | 205 | ||||
-rw-r--r-- | src/pies.rcin | 31 | ||||
-rw-r--r-- | src/progman.c | 1741 | ||||
-rw-r--r-- | src/socket.c | 446 |
12 files changed, 5237 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..8a4684a --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,6 @@ +meta1gram.c +meta1gram.h +meta1gram.output +meta1lex.c +pies +pies.rc diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..52648c8 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,57 @@ +# This file is part of mailfrom filter. +# Copyright (C) 2008, 2009 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/>. + +sbin_PROGRAMS = pies + +pies_SOURCES = \ + depmap.c\ + limits.c\ + meta1gram.y\ + meta1lex.l\ + pies.c\ + progman.c\ + socket.c + +noinst_HEADERS = \ + meta1gram.h\ + meta1lex.h\ + pies.h + +EXTRA_DIST = pies.rcin +noinst_DATA = pies.rc +DISTCLEANFILES = pies.rc +.rcin.rc: + $(AM_V_GEN)sed 's|SBINDIR|$(sbindir)|g' $< > $@ + +meta1lex.c: meta1gram.h + +INCLUDES = \ + $(MAILUTILS_INCLUDES)\ + $(MU_COMMON_INCLUDES)\ + -I$(top_srcdir)/lib\ + -I$(top_srcdir)/gnu + +LDADD = \ + ../lib/libmf.a\ + ../gnu/libgnu.a\ + $(MAILUTILS_LIBS)\ + $(MF_PROCTITLE_LIBS) + +AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"\ + -DSTATEDIR=\"$(localstatedir)\" + +AM_YFLAGS=-dvt -pmeta1 +AM_LFLAGS=-dvp -Pmeta1 -olex.yy.c diff --git a/src/depmap.c b/src/depmap.c new file mode 100644 index 0000000..76b492f --- /dev/null +++ b/src/depmap.c @@ -0,0 +1,170 @@ +/* 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 of the License, 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" + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif +#define BITS_PER_WORD (sizeof(unsigned)*CHAR_BIT) +#define MAXTABLE 32767 + +#define WORDSIZE(n) (((n) + BITS_PER_WORD - 1) / BITS_PER_WORD) +#define SETBIT(x, i) ((x)[(i)/BITS_PER_WORD] |= (1<<((i) % BITS_PER_WORD))) +#define RESETBIT(x, i) ((x)[(i)/BITS_PER_WORD] &= ~(1<<((i) % BITS_PER_WORD))) +#define BITISSET(x, i) (((x)[(i)/BITS_PER_WORD] & (1<<((i) % BITS_PER_WORD))) != 0) + +void +TC (unsigned *R, int n) +{ + register int rowsize; + register unsigned mask; + register unsigned *rowj; + register unsigned *rp; + register unsigned *rend; + register unsigned *ccol; + + unsigned *relend; + unsigned *cword; + unsigned *rowi; + + rowsize = WORDSIZE (n) * sizeof (unsigned); + relend = (unsigned *) ((char *) R + (n * rowsize)); + + cword = R; + mask = 1; + rowi = R; + while (rowi < relend) + { + ccol = cword; + rowj = R; + + while (rowj < relend) + { + if (*ccol & mask) + { + rp = rowi; + rend = (unsigned *) ((char *) rowj + rowsize); + + while (rowj < rend) + *rowj++ |= *rp++; + } + else + { + rowj = (unsigned *) ((char *) rowj + rowsize); + } + + ccol = (unsigned *) ((char *) ccol + rowsize); + } + + mask <<= 1; + if (mask == 0) + { + mask = 1; + cword++; + } + rowi = (unsigned *) ((char *) rowi + rowsize); + } +} + +struct pies_depmap +{ + unsigned nrows; + unsigned rowlen; + unsigned r[1]; +}; + +pies_depmap_t +depmap_alloc (unsigned count) +{ + size_t size = (count + BITS_PER_WORD - 1) / BITS_PER_WORD; + pies_depmap_t dmap = xzalloc (sizeof (*dmap) - 1 + + count * size * sizeof (unsigned)); + dmap->nrows = count; + dmap->rowlen = size; + return dmap; +} + +pies_depmap_t +depmap_copy (pies_depmap_t dpm) +{ + pies_depmap_t copy = depmap_alloc (dpm->nrows); + memcpy (copy->r, dpm->r, dpm->nrows * dpm->rowlen * sizeof (unsigned)); + return copy; +} + +static unsigned * +depmap_rowptr (pies_depmap_t dmap, unsigned row) +{ + return dmap->r + dmap->rowlen * row; +} + +void +depmap_set (pies_depmap_t dmap, unsigned row, unsigned col) +{ + unsigned *rptr = depmap_rowptr (dmap, row); + SETBIT (rptr, col); +} + +int +depmap_isset (pies_depmap_t dmap, unsigned row, unsigned col) +{ + unsigned *rptr = depmap_rowptr (dmap, row); + return BITISSET (rptr, col); +} + +void +depmap_tc (pies_depmap_t dmap) +{ + TC (dmap->r, dmap->nrows); +} + +struct pies_depmap_pos +{ + enum pies_depmap_direction dir; + unsigned coord[2]; +}; + +unsigned +depmap_next (pies_depmap_t dmap, pies_depmap_pos_t pos) +{ + for (pos->coord[pos->dir]++; pos->coord[pos->dir] < dmap->nrows; + pos->coord[pos->dir]++) + if (depmap_isset (dmap, pos->coord[0], pos->coord[1])) + break; + + return pos->coord[pos->dir] == dmap->nrows ? + (unsigned) -1 : pos->coord[pos->dir]; +} + +unsigned +depmap_first (pies_depmap_t dmap, enum pies_depmap_direction dir, + unsigned coord, pies_depmap_pos_t *ppos) +{ + pies_depmap_pos_t pos = xmalloc (sizeof *pos); + *ppos = pos; + pos->dir = dir; + pos->coord[!pos->dir] = coord; + pos->coord[pos->dir] = -1; + return depmap_next (dmap, pos); +} + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ +/* EOF */ diff --git a/src/limits.c b/src/limits.c new file mode 100644 index 0000000..90d6459 --- /dev/null +++ b/src/limits.c @@ -0,0 +1,299 @@ +/* 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> + +#define SET_LIMIT_AS 0x0001 +#define SET_LIMIT_CPU 0x0002 +#define SET_LIMIT_DATA 0x0004 +#define SET_LIMIT_FSIZE 0x0008 +#define SET_LIMIT_NPROC 0x0010 +#define SET_LIMIT_CORE 0x0020 +#define SET_LIMIT_MEMLOCK 0x0040 +#define SET_LIMIT_NOFILE 0x0080 +#define SET_LIMIT_RSS 0x0100 +#define SET_LIMIT_STACK 0x0200 +#define SET_LIMIT_LOGINS 0x0400 +#define SET_LIMIT_PRIO 0x0800 + +struct limits_rec { + unsigned set; + rlim_t limit_as; + rlim_t limit_cpu; + rlim_t limit_data; + rlim_t limit_fsize; + rlim_t limit_nproc; + rlim_t limit_core; + rlim_t limit_memlock; + rlim_t limit_nofile; + rlim_t limit_rss; + rlim_t limit_stack; + int limit_logins; + int limit_prio; +}; + +int +do_set_limit (int rlimit, rlim_t limit) +{ + struct rlimit rlim; + + MU_DEBUG2 (pies_debug, MU_DEBUG_TRACE1, + "Setting limit %d to %lu\n", rlimit, (unsigned long) limit); + rlim.rlim_cur = limit; + rlim.rlim_max = limit; + + if (setrlimit(rlimit, &rlim)) + { + mu_diag_output (MU_DIAG_NOTICE, _("error setting limit: %s"), + mu_strerror (errno)); + return 1; + } + return 0; +} + +static int +set_prio (int prio) +{ + MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "Setting priority to %d\n", prio); + if (setpriority (PRIO_PROCESS, 0, prio)) + { + mu_diag_output (MU_DIAG_NOTICE, _("error setting priority: %s"), + mu_strerror (errno)); + return 1; + } + return 0; +} + +/* Counts the number of user logins and check against the limit */ +static int +check_logins (const char *name, int limit) +{ + mu_diag_output (MU_DIAG_NOTICE, _("L limit is not implemented")); + return 0; +} + +int +set_limits (const char *name, struct limits_rec *lrec) +{ + int rc = 0; + + if (!lrec) + return 0; + + MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "Setting limits for %s\n", name); + +#if defined(RLIMIT_AS) + if (lrec->set & SET_LIMIT_AS) + rc |= do_set_limit(RLIMIT_AS, lrec->limit_as); +#endif +#if defined(RLIMIT_CPU) + if (lrec->set & SET_LIMIT_CPU) + rc |= do_set_limit(RLIMIT_CPU, lrec->limit_cpu); +#endif +#if defined(RLIMIT_DATA) + if (lrec->set & SET_LIMIT_DATA) + rc |= do_set_limit(RLIMIT_DATA, lrec->limit_data); +#endif +#if defined(RLIMIT_FSIZE) + if (lrec->set & SET_LIMIT_FSIZE) + rc |= do_set_limit(RLIMIT_FSIZE, lrec->limit_fsize); +#endif +#if defined(RLIMIT_NPROC) + if (lrec->set & SET_LIMIT_NPROC) + rc |= do_set_limit(RLIMIT_NPROC, lrec->limit_nproc); +#endif +#if defined(RLIMIT_CORE) + if (lrec->set & SET_LIMIT_CORE) + rc |= do_set_limit(RLIMIT_CORE, lrec->limit_core); +#endif +#if defined(RLIMIT_MEMLOCK) + if (lrec->set & SET_LIMIT_MEMLOCK) + rc |= do_set_limit(RLIMIT_MEMLOCK, lrec->limit_memlock); +#endif +#if defined(RLIMIT_NOFILE) + if (lrec->set & SET_LIMIT_NOFILE) + rc |= do_set_limit(RLIMIT_NOFILE, lrec->limit_nofile); +#endif +#if defined(RLIMIT_RSS) + if (lrec->set & SET_LIMIT_RSS) + rc |= do_set_limit(RLIMIT_RSS, lrec->limit_rss); +#endif +#if defined(RLIMIT_STACK) + if (lrec->set & SET_LIMIT_STACK) + rc |= do_set_limit(RLIMIT_STACK, lrec->limit_stack); +#endif + if (lrec->set & SET_LIMIT_LOGINS) + rc |= check_logins(name, lrec->limit_logins); + if (lrec->set & SET_LIMIT_PRIO) + rc |= set_prio(lrec->limit_logins); + return rc; +} + +int +getlimit (char **ptr, rlim_t *rlim, int mul) +{ + if (**ptr == '-') + { + *rlim = RLIM_INFINITY; + ++*ptr; + } + else + { + unsigned long val; + + val = strtoul (*ptr, ptr, 10); + if (val == 0) + return 1; + *rlim = val * mul; + } + return 0; +} + +/* Parse limits string and fill appropriate fields in lrec. + + The string consists of _commands_, optionally separated by any amount + of whitespace. A command has the following form: + + [AaCcDdFfMmNnRrSsTtUuLlPp](-|[0-9]+) + + i.e. a letter followed by number or a dash. The latters stands for + 'unlimited'. Commands are interpreted as follows: + + Command ulimit setrlimit() The limit it sets + option arg + ------------------------------------------------------------- + [Aa] a RLIMIT_AS max address space (KB) + [Cc] c RLIMIT_CORE max core file size (KB) + [Dd] d RLIMIT_DATA max data size (KB) + [Ff] f RLIMIT_FSIZE Maximum filesize (KB) + [Mm] m RLIMIT_MEMLOCK max locked-in-memory address + space (KB) + [Nn] n RLIMIT_NOFILE max number of open files + [Rr] r RLIMIT_RSS max resident set size (KB) + [Ss] s RLIMIT_STACK max stack size (KB) + [Tt] t RLIMIT_CPU max CPU time (MIN) + [Uu] u RLIMIT_NPROC max number of processes + [Ll] l (none) max number of logins (N/A) + [Pp] p (none) process priority -20..20 + (negative = high priority) + */ +int +parse_limits (limits_record_t *plrec, char *str, char **endp) +{ + int c; + struct limits_rec *lrec = xmalloc (sizeof (*lrec)); + *plrec = lrec; + lrec->set = 0; + while ((c = *str++)) + { + if (c == ' ' || c == '\t') + continue; + switch (c) + { + case 'a': + case 'A': + /* RLIMIT_AS - max address space (KB) */ + if (!getlimit (&str, &lrec->limit_as, 1024)) + lrec->set |= SET_LIMIT_AS; + break; + + case 't': + case 'T': + /* RLIMIT_CPU - max CPU time (MIN) */ + if (!getlimit (&str, &lrec->limit_cpu, 60)) + lrec->set |= SET_LIMIT_CPU; + break; + + case 'd': + case 'D': + /* RLIMIT_DATA - max data size (KB) */ + if (!getlimit (&str, &lrec->limit_data, 1024)) + lrec->set |= SET_LIMIT_DATA; + break; + + case 'f': + case 'F': + /* RLIMIT_FSIZE - Maximum filesize (KB) */ + if (!getlimit (&str, &lrec->limit_fsize, 1024)) + lrec->set |= SET_LIMIT_FSIZE; + break; + + case 'u': + case 'U': + /* RLIMIT_NPROC - max number of processes */ + if (!getlimit (&str, &lrec->limit_nproc, 1)) + lrec->set |= SET_LIMIT_NPROC; + break; + + case 'c': + case 'C': + /* RLIMIT_CORE - max core file size (KB) */ + if (!getlimit (&str, &lrec->limit_core, 1024)) + lrec->set |= SET_LIMIT_CORE; + break; + + case 'm': + case 'M': + /* RLIMIT_MEMLOCK - max locked-in-memory + * address space (KB) + */ + if (!getlimit (&str, &lrec->limit_memlock, 1024)) + lrec->set |= SET_LIMIT_MEMLOCK; + break; + + case 'n': + case 'N': + /* RLIMIT_NOFILE - max number of open files */ + if (!getlimit (&str, &lrec->limit_nofile, 1)) + lrec->set |= SET_LIMIT_NOFILE; + break; + + case 'r': + case 'R': + /* RLIMIT_RSS - max resident set size (KB) */ + if (!getlimit (&str, &lrec->limit_rss, 1024)) + lrec->set |= SET_LIMIT_RSS; + break; + + case 's': + case 'S': + /* RLIMIT_STACK - max stack size (KB) */ + if (!getlimit (&str, &lrec->limit_stack, 1024)) + lrec->set |= SET_LIMIT_STACK; + break; + + case 'l': + case 'L': + lrec->limit_logins = strtol (str, &str, 10); + if (lrec->limit_logins >= 0) + lrec->set |= SET_LIMIT_LOGINS; + break; + + case 'p': + case 'P': + lrec->limit_prio = strtol (str, &str, 10); + if (lrec->limit_prio > 0) + lrec->set |= SET_LIMIT_PRIO; + break; + + default: + *endp = str-1; + return 1; + } + } + return 0; +} + diff --git a/src/meta1gram.y b/src/meta1gram.y new file mode 100644 index 0000000..4966634 --- /dev/null +++ b/src/meta1gram.y @@ -0,0 +1,439 @@ +%{ +/* MeTA1 configuration parser for 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/>. */ + +/* This file implements a grammar for parsing MeTA1 main configuration file, + and a set of functions for converting its statements into Pies + configuration statements. */ + +#include "pies.h" +#include "meta1lex.h" + +/* FIXME: Use mu_opool_alloc? */ +static mu_config_value_t * +create_value (int type) +{ + mu_config_value_t *val = mu_alloc (sizeof (*val)); + val->type = type; + return val; +} + +static mu_config_value_t * +config_value_dup (mu_config_value_t *src) +{ + if (!src) + return NULL; + else + { + mu_config_value_t *val = mu_alloc (sizeof (*val)); + *val = *src; + return val; + } +} + +static mu_cfg_node_t * +alloc_node (enum mu_cfg_node_type type, mu_cfg_locus_t *loc, + const char *tag, mu_config_value_t *label, + mu_cfg_node_t *node) +{ + char *p; + mu_cfg_node_t *np; + size_t size = sizeof *np + strlen (tag) + 1; + np = mu_alloc (size); + np->type = type; + np->locus = *loc; + p = (char*) (np + 1); + np->tag = p; + strcpy (p, tag); + np->label = label; + np->node = node; + np->next = NULL; + return np; +} + +static mu_cfg_node_t *translate_component (mu_cfg_node_t *); + +mu_cfg_node_t *meta1_parse_head; + +%} + +%union { + mu_cfg_node_t node; + mu_cfg_node_t *pnode; + mu_config_value_t *value; + struct { mu_cfg_node_t *head, *tail; } nodelist; + char *string; + unsigned long number; + mu_list_t list; +} + +%token <string> META1_IDENT META1_STRING META1_NUMBER + +%type <nodelist> stmtlist +%type <pnode> stmt simple block +%type <list> slist list values +%type <string> string ident +%type <value> value + +%% + +input : stmtlist + { + mu_cfg_node_t *node; + meta1_parse_head = NULL; + for (node = $1.head; node; node = node->next) + { + mu_cfg_node_t *new_node = translate_component (node); + if (new_node) + { + new_node->next = meta1_parse_head; + meta1_parse_head = new_node; + } + } + } + ; + +stmtlist: stmt + { + $$.head = $$.tail = $1; + } + | stmtlist stmt + { + $$ = $1; + $$.tail->next = $2; + $$.tail = $2; + } + ; + +stmt : simple + | block + ; + +simple : ident '=' value opt_sc + { + $$ = alloc_node (mu_cfg_node_param, &meta1_locus, + $1, $3, + NULL); + } + ; + +block : ident tag '{' stmtlist '}' opt_sc + { + /* FIXME: tag is currently ignored */ + $$ = alloc_node (mu_cfg_node_tag, &meta1_locus, + $1, NULL, + $4.head); + } + ; + +tag : /* empty */ + | META1_IDENT + ; + +ident : META1_IDENT + ; + +value : string + { + $$ = create_value (MU_CFG_STRING); + $$->v.string = $1; + } + | list + { + $$ = create_value (MU_CFG_LIST); + $$->v.list = $1; + } + | META1_NUMBER + { + $$ = create_value (MU_CFG_STRING); + $$->v.string = $1; + } + ; + +string : META1_IDENT + | slist + { + mu_iterator_t itr; + mu_list_get_iterator ($1, &itr); + + meta1_line_begin (); + for (mu_iterator_first (itr); + !mu_iterator_is_done (itr); mu_iterator_next (itr)) + { + char *p; + mu_iterator_current (itr, (void**)&p); + meta1_line_add (p, strlen (p)); + } + $$ = meta1_line_finish (); + mu_iterator_destroy (&itr); + mu_list_destroy (&$1); + } + ; + +slist : META1_STRING + { + mu_list_create (&$$); + mu_list_append ($$, $1); + } + | slist META1_STRING + { + mu_list_append ($1, $2); + $$ = $1; + } + ; + +list : '{' values '}' + { + $$ = $2; + } + | '{' values ',' '}' + { + $$ = $2; + } + ; + +values : value + { + mu_list_create (&$$); + mu_list_append ($$, $1); + } + | values ',' value + { + mu_list_append ($1, $3); + $$ = $1; + } + ; + +opt_sc : /* empty */ + | ';' + ; + +%% +int +yyerror (char *s) +{ + meta1_parse_error ("%s", s); + return 0; +} + +void +meta1_parser_set_debug () +{ + mu_log_level_t lev = mu_global_debug_level ("meta1"); + if (lev & MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE6)) + yydebug = 1; +} + +struct node_trans +{ + char *name; + char *new_name; + mu_cfg_node_t *(*fun) (const char *, mu_cfg_node_t *); +}; + + +static struct node_trans * +find_node_trans (struct node_trans *tab, const char *name) +{ + for (; tab->name; tab++) + if (strcmp (tab->name, name) == 0) + return tab; + return NULL; +} + +static mu_cfg_node_t * +find_node (mu_cfg_node_t *list, const char *name) +{ + for (; list; list = list->next) + { + if (strcmp (list->tag, name) == 0) + return list; + } + return NULL; +} + +static mu_cfg_node_t * +xlat_listen_socket (const char *name, mu_cfg_node_t *src) +{ + mu_cfg_node_t *p; + mu_config_value_t *val; + + meta1_line_begin (); + p = find_node (src->node, "type"); + if (!p || !p->label || p->label->type != MU_CFG_STRING) + return NULL; + meta1_line_add (p->label->v.string, strlen (p->label->v.string)); + meta1_line_add ("://", 3); + if (strcmp (p->label->v.string, "inet") == 0) + { + const char *addr; + p = find_node (src->node, "address"); + if (p) + { + if (p->label->type != MU_CFG_STRING) + return NULL; + addr = p->label->v.string; + } + else + addr = "0.0.0.0"; + meta1_line_add (addr, strlen (addr)); + meta1_line_add (":", 1); + p = find_node (src->node, "port"); + if (p->label->type != MU_CFG_STRING) + return NULL; + meta1_line_add (p->label->v.string, strlen (p->label->v.string)); + } + else if (strcmp (p->label->v.string, "unix") == 0) + { + p = find_node (src->node, "path"); + if (!p || p->label->type != MU_CFG_STRING) + return NULL; + meta1_line_add (p->label->v.string, strlen (p->label->v.string)); + /* FIXME: Other substatements: + listen_socket { + type=unix; + path = /tmp/socket; + umask = 077; + user = user; + group = group; + } + */ + } + val = create_value (MU_CFG_STRING); + val->v.string = meta1_line_finish (); + return alloc_node (mu_cfg_node_param, &src->locus, "socket", val, NULL); +} + +static struct node_trans root_node_trans[] = { + { "listen_socket", "socket", xlat_listen_socket }, + { "start_action", "mode" }, + { "pass_fd_socket", "pass-fd-socket" }, + { "user", "user" }, + { "path", "program" }, + { "arguments", "command" }, + { "restart_dependencies", "dependents", }, + { NULL } +}; + +static mu_cfg_node_t * +create_string_node (const char *tag, const char *str, mu_cfg_locus_t *locus) +{ + mu_config_value_t *val = create_value (MU_CFG_STRING); + + 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_redir_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) + { + if (nt->fun) + dst = nt->fun (nt->new_name, src); + else + dst = alloc_node (mu_cfg_node_param, &src->locus, + 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, const char *name) +{ + mu_cfg_node_t *head = NULL, *tail = NULL; + mu_cfg_locus_t *locus = &src->locus; + + for (; src; src = src->next) + { + mu_cfg_node_t *dst = translate_node (src); + if (dst) + { + if (tail) + tail->next = dst; + else + head = dst; + tail = dst; + } + } + if (head) + { + /* Add common statements: */ + 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 (), locus); + tail->next = node; + tail = node; + + node = create_redir_node ("stderr", META1_QUEUE_DIR (), name, locus); + tail->next = node; + tail = node; + + node = create_string_node ("settle-timeout", "1", locus); + tail->next = node; + tail = node; + } + return head; +} + +static mu_cfg_node_t * +translate_component (mu_cfg_node_t *src) +{ + mu_cfg_node_t *dst = NULL; + 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, val->v.string)); + } + return dst; +} + diff --git a/src/meta1lex.h b/src/meta1lex.h new file mode 100644 index 0000000..8db32f9 --- /dev/null +++ b/src/meta1lex.h @@ -0,0 +1,31 @@ +/* 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/>. */ + +extern mu_cfg_locus_t meta1_locus; +extern size_t meta1_error_count; +extern mu_cfg_node_t *meta1_parse_head; +extern mu_cfg_tree_t *meta1_parse_tree; +extern char *meta1_queue_dir; + +char *meta1_string (const char *str, size_t len); +void meta1_line_add (const char *text, size_t len); +void meta1_line_add_unescape_last (const char *text, size_t len); +void meta1_line_add_unescape_hex (const char *text, size_t len); +void meta1_line_begin (void); +char *meta1_line_finish (); +void meta1_parse_error (const char *fmt, ...); +int meta1_config_parse (const char *name); + diff --git a/src/meta1lex.l b/src/meta1lex.l new file mode 100644 index 0000000..312a1fd --- /dev/null +++ b/src/meta1lex.l @@ -0,0 +1,231 @@ +%{ +/* MeTA1 configuration lexer for 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/>. */ + +/* This file implements a lexical analyzer for MeTA1 main configuration file. + */ + +#include "pies.h" +#include "meta1gram.h" +#include "meta1lex.h" + +mu_cfg_locus_t meta1_locus; +size_t meta1_error_count; +mu_opool_t meta1_pool; +char *meta1_queue_dir; + +#define yylval meta1lval +%} + +%x COMMENT STR +X [0-9a-fA-F] +%% + /* C-style comments */ +"/*" BEGIN (COMMENT); +<COMMENT>[^*\n]* /* eat anything that's not a '*' */ +<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ +<COMMENT>\n ++meta1_locus.line; +<COMMENT>"*"+"/" BEGIN (INITIAL); + /* End-of-line comments */ +#.*\n { meta1_locus.line++; } +#.* /* end-of-file comment */; + /* Number */ +0[xX]{X}+ | +0[0-7]+ | +[1-9][0-9]+ { meta1_line_begin (); + meta1_line_add (yytext, yyleng); + yylval.string = meta1_line_finish (); + return META1_NUMBER; } + /* Identifiers (unquoted strings) */ +[a-zA-Z0-9_\./:\*-]+ { meta1_line_begin (); + meta1_line_add (yytext, yyleng); + yylval.string = meta1_line_finish (); + return META1_IDENT; } + /* Quoted strings */ +\"[^\\"\n]*\" { meta1_line_begin (); + meta1_line_add (yytext + 1, yyleng - 2); + yylval.string = meta1_line_finish (); + return META1_STRING; } +\"[^\\"\n]*\\x{X}{1,2} { BEGIN(STR); + meta1_line_begin (); + meta1_line_add_unescape_hex (yytext + 1, yyleng - 1); + } +\"[^\\"\n]*\\. { BEGIN(STR); + meta1_line_begin (); + meta1_line_add_unescape_last (yytext + 1, yyleng - 1); } +<STR>[^\\"\n]*\\x{X}{1,2} { meta1_line_add_unescape_hex (yytext, yyleng); } +<STR>[^\\"\n]*\\. { meta1_line_add_unescape_last (yytext, yyleng); } +<STR>[^\\"\n]*\" { BEGIN (INITIAL); + if (yyleng > 1) + meta1_line_add (yytext, yyleng - 1); + yylval.string = meta1_line_finish (); + return META1_STRING; } +<STR>[^\\"\n]*\n { BEGIN (INITIAL); + meta1_parse_error (_("newline in a string")); + meta1_line_add (yytext, yyleng - 1); + yylval.string = meta1_line_finish (); + return META1_STRING; } + /* Other tokens */ +[ \t\f][ \t\f]* |