aboutsummaryrefslogtreecommitdiff
path: root/src/meta1gram.y
diff options
context:
space:
mode:
Diffstat (limited to 'src/meta1gram.y')
-rw-r--r--src/meta1gram.y439
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;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.