diff options
Diffstat (limited to 'src/meta1gram.y')
-rw-r--r-- | src/meta1gram.y | 439 |
1 files changed, 439 insertions, 0 deletions
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; +} + |