%{ /* 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 . */ /* 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 META1_IDENT META1_STRING META1_NUMBER %type stmtlist %type stmt simple block %type slist list values %type string ident %type 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; }