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

Return to:

Send suggestions and report system problems to the System administrator.