diff options
Diffstat (limited to 'src/meta1parse.c')
-rw-r--r-- | src/meta1parse.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/src/meta1parse.c b/src/meta1parse.c new file mode 100644 index 0000000..059ea54 --- /dev/null +++ b/src/meta1parse.c @@ -0,0 +1,360 @@ +/* This file is part of GNU Pies. + Copyright (C) 2016 Sergey Poznyakoff + + GNU Pies 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. + + GNU Pies 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 GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ + +#include "pies.h" + +char *meta1_queue_dir; + +#define META1_QUEUE_DIR() \ + (meta1_queue_dir ? meta1_queue_dir : "/var/spool/meta1") + +static void +setflag (int *flag, char const *var, int bit) +{ + char *p = getenv (var); + if (p && (*p - '0') > 0) + *flag |= bit; +} + + +static enum grecs_tree_recurse_res +freeproc (enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) +{ + switch (op) + { + case grecs_tree_recurse_set: + case grecs_tree_recurse_post: + grecs_node_unlink (node); + grecs_node_free (node); + break; + case grecs_tree_recurse_pre: + /* descend into the subtree */ + break; + } + return grecs_tree_recurse_ok; +} + +int +grecs_subtree_free (struct grecs_node *node) +{ + if (!node) + return 0; + if (node->type != grecs_node_block) + { + errno = EINVAL; + return 1; + } + grecs_tree_recurse (node, freeproc, node); + return 0; +} + + +static int +xlat_start_action (struct grecs_node *node) +{ + if (node->type != grecs_node_stmt) + return -1; + if (strcmp (node->v.value->v.string, "wait") == 0) + { + node->v.value->v.string = grecs_strdup ("exec"); + } + return 0; +} + +enum substatement_status + { + substatement_success, + substatement_error, + substatement_not_found + }; + +static struct grecs_node * +simple_find_node (struct grecs_node *node, char const *name) +{ + for (node = node->down; node; node = node->next) + if (strcmp (node->ident, name) == 0) + break; + return node; +} + +static enum substatement_status +substatement_find (struct grecs_node *node, char const *name, int type, + int req, grecs_value_t **ret) +{ + struct grecs_node *np; + + np = simple_find_node (node, name); + if (!np) + { + if (req) + grecs_error (&node->locus, 0, _("no \"%s\" statement in block"), + name); + return substatement_not_found; + } + + if (node->type != grecs_node_block) + { + grecs_error (&node->locus, 0, _("unexpected scalar statement")); + return substatement_error; + } + + if (assert_grecs_value_type (&np->v.value->locus, np->v.value, type)) + return substatement_error; + + *ret = np->v.value; + + return substatement_success; +} + +static int +translate_url_param (struct grecs_node *node, char const *name, + struct grecs_txtacc *acc) +{ + struct grecs_value *np; + + switch (substatement_find (node, name, GRECS_TYPE_STRING, 0, &np)) + { + case substatement_success: + grecs_txtacc_grow_char (acc, ';'); + grecs_txtacc_grow_string (acc, name + 1); + grecs_txtacc_grow_char (acc, '='); + grecs_txtacc_grow_string (acc, np->v.string); + break; + + case substatement_not_found: + break; + + case substatement_error: + return -1; + } + return 0; +} + +static int +xlat_listen_socket_i (struct grecs_node *node, char const *type, + struct grecs_txtacc *acc) +{ + struct grecs_value *val, *vp; + char *url; + + grecs_txtacc_grow_string (acc, type); + grecs_txtacc_grow (acc, "://", 3); + + if (strcmp (type, "inet") == 0) + { + const char *addr; + + switch (substatement_find (node, "address", GRECS_TYPE_STRING, 0, &vp)) + { + case substatement_success: + addr = vp->v.string; + break; + + case substatement_not_found: + addr = "0.0.0.0"; + break; + + case substatement_error: + return -1; + } + + grecs_txtacc_grow_string (acc, addr); + grecs_txtacc_grow_char (acc, ':'); + + if (substatement_find (node, "port", GRECS_TYPE_STRING, 1, &vp) != + substatement_success) + return -1; + grecs_txtacc_grow_string (acc, vp->v.string); + } + else if (strcmp (type, "unix") == 0) + { + /* listen_socket { + type=unix; + path = /tmp/socket; + umask = 077; + user = user; + group = group; + } + */ + if (substatement_find (node, "path", GRECS_TYPE_STRING, 1, &vp) != + substatement_success) + return -1; + + grecs_txtacc_grow_string (acc, vp->v.string); + if (translate_url_param (node, "user", acc)) + return -1; + if (translate_url_param (node, "group", acc)) + return -1; + if (translate_url_param (node, "umask", acc)) + return -1; + } + else + { + grecs_error (&node->locus, 0, _("unsupported type")); + return -1; + } + + grecs_txtacc_grow_char (acc, 0); + url = grecs_txtacc_finish (acc, 1); + + val = grecs_malloc (sizeof(*val)); + val->type = GRECS_TYPE_STRING; + val->locus = node->locus; + val->v.string = url; + + grecs_subtree_free (node->down); + + node->type = grecs_node_stmt; + node->v.value = val; + return 0; +} + +static int +xlat_listen_socket (struct grecs_node *node) +{ + int rc; + struct grecs_value *val; + struct grecs_txtacc *acc; + + if (node->type != grecs_node_block) + return -1; + + if (substatement_find (node, "type", GRECS_TYPE_STRING, 1, &val) != + substatement_success) + return -1; + acc = grecs_txtacc_create (); + rc = xlat_listen_socket_i (node, val->v.string, acc); + grecs_txtacc_free (acc); + return rc; +} + + +struct meta1_translator +{ + char const *old_name; + char const *new_name; + int (*translate) (struct grecs_node *); +}; + +static struct meta1_translator transtab[] = { + { "start_action", "mode", xlat_start_action }, + { "listen_socket", "socket", xlat_listen_socket }, + { "pass_fd_socket", "pass-fd-socket" }, + { "user", "user" }, + { "path", "program" }, + { "arguments", "command" }, + { "restart_dependencies", "dependents", }, + { NULL } +}; + +static struct meta1_translator * +meta1_translator_lookup (const char *name) +{ + struct meta1_translator *p; + + for (p = transtab; p->old_name; p++) + if (strcmp (p->old_name, name) == 0) + return p; + return NULL; +} + +static int +meta1_translate_stmt (struct grecs_node *stmt, struct component *comp) +{ + struct meta1_translator *trans = meta1_translator_lookup (stmt->ident); + struct grecs_keyword *kwp; + + if (!trans) + return 0; + if (trans->translate && trans->translate (stmt)) + return -1; + if (stmt->type != grecs_node_stmt) + return -1; + + kwp = find_component_keyword (trans->new_name); + grecs_process_ident (kwp, stmt->v.value, comp, &stmt->locus); + return 0; +} + +static int +meta1_translate_node (struct grecs_node *node) +{ + struct component *comp; + struct grecs_node *stmt; + size_t len; + int err = 0; + + comp = component_create (node->ident); + for (stmt = node->down; stmt; stmt = stmt->next) + { + if (meta1_translate_stmt (stmt, comp)) + ++err; + } + if (err) + { + component_free (comp); + return -1; + } + + comp->privs.allgroups = 1; + comp->dir = META1_QUEUE_DIR (); + comp->redir[RETR_ERR].type = redir_file; + comp->redir[RETR_ERR].v.file = NULL; + len = 0; + grecs_asprintf (&comp->redir[RETR_ERR].v.file, &len, + "%s/%s.log", META1_QUEUE_DIR (), comp->tag); + component_finish (comp, &node->locus); + return 0; +} + +static int +meta1_translate_node_list (struct grecs_node *node) +{ + int err = 0; + while (node) + { + if (meta1_translate_node (node)) + ++err; + node = node->next; + } + return err; +} + +int +meta1_config_parse (const char *name) +{ + struct grecs_node *subtree; + int traceflags = 0; + int rc; + + setflag (&traceflags, "META1_DEBUG_YACC", GRECS_TRACE_GRAM); + setflag (&traceflags, "META1_DEBUG_LEX", GRECS_TRACE_LEX); + + grecs_error_count = 0; + grecs_current_locus_point.file = grecs_install_text (name); + grecs_current_locus_point.line = 1; + grecs_current_locus_point.col = 0; + subtree = grecs_meta1_parser (name, traceflags); + + if (!subtree) + return -1; + + rc = meta1_translate_node_list (subtree->down); + + grecs_node_free (subtree); + + return rc; +} |