%{ /* MeTA1 configuration parser for Pies. 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 . */ /* 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" #define META1_QUEUE_DIR() \ (meta1_queue_dir ? meta1_queue_dir : "/var/spool/meta1") enum meta1_stmt_type { meta1_simple, meta1_block }; struct meta1_stmt { struct meta1_stmt *next; grecs_locus_t locus; enum meta1_stmt_type type; const char *ident; union { grecs_value_t *value; struct meta1_stmt *list; } v; }; struct meta1_stmt * meta1_stmt_create (enum meta1_stmt_type type, const char *ident) { struct meta1_stmt *p = xmalloc (sizeof (*p)); p->next = NULL; p->type = type; p->ident = ident; p->locus = meta1_locus; return p; } static struct meta1_stmt * _reverse (struct meta1_stmt *list, struct meta1_stmt **root) { struct meta1_stmt *next; if (list->next == NULL) { *root = list; return list; } next = _reverse (list->next, root); next->next = list; list->next = NULL; return list; } static struct meta1_stmt * reverse (struct meta1_stmt *in) { struct meta1_stmt *root; if (!in) return in; _reverse (in, &root); return root; } static void meta1_translate (struct meta1_stmt *); %} %union { char *string; gl_list_t list; grecs_value_t *value; struct meta1_stmt *stmt; } %token META1_IDENT META1_STRING META1_NUMBER %type slist values list %type value %type string ident %type stmtlist stmt simple block %% input : stmtlist { struct meta1_stmt *stmt; for (stmt = $1; stmt; stmt = stmt->next) meta1_translate (stmt); } ; stmtlist: stmt { $$ = $1; } | stmtlist stmt { $2->next = $1; $$ = $2; } ; stmt : simple | block ; simple : ident '=' value opt_sc { $$ = meta1_stmt_create (meta1_simple, $1); $$->v.value = $3; } ; block : ident tag '{' stmtlist '}' opt_sc { $$ = meta1_stmt_create (meta1_block, $1); $$->v.list = reverse ($4); } ; tag : /* empty */ | META1_IDENT ; ident : META1_IDENT ; value : string { $$ = xmalloc (sizeof (*$$)); $$->type = GRECS_TYPE_STRING; $$->v.string = $1; } | list { $$ = xmalloc (sizeof (*$$)); $$->type = GRECS_TYPE_LIST; $$->v.list = $1; } | META1_NUMBER { $$ = xmalloc (sizeof (*$$)); $$->type = GRECS_TYPE_STRING; $$->v.string = $1; } ; string : META1_IDENT | slist { const void *p; gl_list_iterator_t itr = gl_list_iterator ($1); meta1_line_begin (); while (gl_list_iterator_next (&itr, &p, NULL)) meta1_line_add (p, strlen (p)); gl_list_iterator_free (&itr); $$ = meta1_line_finish (); } ; slist : META1_STRING { $$ = gl_list_create_empty (&gl_linked_list_implementation, NULL, NULL, NULL, true); gl_list_add_last ($$, $1); } | slist META1_STRING { gl_list_add_last ($1, $2); $$ = $1; } ; list : '{' values '}' { $$ = $2; } | '{' values ',' '}' { $$ = $2; } ; values : value { $$ = gl_list_create_empty (&gl_linked_list_implementation, NULL, NULL, NULL, true); gl_list_add_last ($$, $1); } | values ',' value { gl_list_add_last ($1, $3); $$ = $1; } ; opt_sc : /* empty */ | ';' ; %% int yyerror (char *s) { meta1_parse_error ("%s", s); return 0; } void meta1_parser_set_debug () { char *p = getenv ("META1_DEBUG_YACC"); yydebug = p && (*p - '0') > 0; } static struct meta1_stmt * find_stmt (struct meta1_stmt *stmt, const char *ident) { for (; stmt; stmt = stmt->next) if (strcmp (stmt->ident, ident) == 0) break; return stmt; } struct node_trans { char *name; char *new_name; int (*xlat) (struct meta1_stmt *stmt, struct component *comp); }; 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 int xlat_listen_socket (struct meta1_stmt *stmt, struct component *comp) { struct meta1_stmt *p; grecs_value_t *val; p = find_stmt (stmt->v.list, "type"); if (!p || !p->v.value || p->v.value->type != GRECS_TYPE_STRING) return 1; meta1_line_begin (); meta1_line_add (p->v.value->v.string, strlen (p->v.value->v.string)); meta1_line_add ("://", 3); if (strcmp (p->v.value->v.string, "inet") == 0) { const char *addr; p = find_stmt (stmt->v.list, "address"); if (p) { if (p->v.value->type != GRECS_TYPE_STRING) return 1; addr = p->v.value->v.string; } else addr = "0.0.0.0"; meta1_line_add (addr, strlen (addr)); meta1_line_add (":", 1); p = find_stmt (stmt->v.list, "port"); if (p->v.value->type != GRECS_TYPE_STRING) return 1; meta1_line_add (p->v.value->v.string, strlen (p->v.value->v.string)); } else if (strcmp (p->v.value->v.string, "unix") == 0) { p = find_stmt (stmt->v.list, "path"); if (!p || p->v.value->type != GRECS_TYPE_STRING) return 1; meta1_line_add (p->v.value->v.string, strlen (p->v.value->v.string)); /* FIXME: Other substatements: listen_socket { type=unix; path = /tmp/socket; umask = 077; user = user; group = group; } */ } val = xmalloc (sizeof (*val)); val->type = GRECS_TYPE_STRING; val->v.string = meta1_line_finish (); stmt->type = meta1_simple; stmt->v.value = val; return 0; } 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 void meta1_translate_stmt (struct meta1_stmt *stmt, struct component *comp) { struct grecs_keyword *kwp; struct node_trans *nt = find_node_trans (root_node_trans, stmt->ident); if (!nt) return; kwp = find_component_keyword (nt->new_name); if (!kwp) abort (); if (nt->xlat && nt->xlat (stmt, comp)) return; grecs_process_ident (kwp, stmt->v.value, comp, &stmt->locus); } static void meta1_translate (struct meta1_stmt *stmt) { struct component *comp; struct meta1_stmt *p; if (stmt->type != meta1_block) return; comp = component_create (stmt->ident); for (p = stmt->v.list; p; p = p->next) { meta1_translate_stmt (p, comp); } comp->privs.allgroups = 1; comp->dir = META1_QUEUE_DIR (); comp->settle_timeout = 1; comp->redir[RETR_ERR].type = redir_file; comp->redir[RETR_ERR].v.file = xasprintf ("%s/%s.log", META1_QUEUE_DIR (), comp->tag); component_finish (comp, &stmt->locus); }