From 264e71a6f1c03a06f38be7a121c8ce1e6bfbf298 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Thu, 20 Feb 2014 23:16:25 +0100 Subject: [PATCH] store: Added a frame-work for object lookups. store_lookup currently provides low-level functionality for matching store objects based on their various attributes. --- src/Makefile.am | 1 + src/core/store_lookup.c | 309 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 310 insertions(+) create mode 100644 src/core/store_lookup.c diff --git a/src/Makefile.am b/src/Makefile.am index 77ce39f..8bd8214 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,6 +67,7 @@ libsysdb_la_SOURCES = \ core/plugin.c include/core/plugin.h \ core/store.c include/core/store.h \ core/store-private.h \ + core/store_lookup.c \ core/data.c include/core/data.h \ frontend/connection.c include/frontend/connection.h \ frontend/connection-private.h \ diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c new file mode 100644 index 0000000..64145ee --- /dev/null +++ b/src/core/store_lookup.c @@ -0,0 +1,309 @@ +/* + * SysDB - src/core/store_lookup.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This module implements operators which may be used to select contents of + * the store by matching various attributes of the stored objects. For now, a + * simple full table scan is supported only. + */ + +#include "sysdb.h" +#include "core/store-private.h" + +#include + +#include +#include + +#include + +/* + * private data types + */ + +/* match the name of something */ +typedef struct { + const char *name; + regex_t *name_re; +} name_matcher_t; + +/* matcher base type */ +typedef struct { + /* type of the matcher */ + int type; +} matcher_t; +#define M(m) ((matcher_t *)(m)) + +/* logical operator matcher */ +typedef struct { + matcher_t super; + + /* left and right hand operands */ + matcher_t *left; + matcher_t *right; +} op_matcher_t; +#define OP_M(m) ((op_matcher_t *)(m)) + +/* match any type of object by it's base information */ +typedef struct { + matcher_t super; + + /* match by the name of the object */ + name_matcher_t name; +} obj_matcher_t; +#define OBJ_M(m) ((obj_matcher_t *)(m)) + +/* match attributes */ +typedef struct { + obj_matcher_t super; + /* XXX: this needs to be more flexible; + * add support for type-specific operators */ + name_matcher_t value; +} attr_matcher_t; +#define ATTR_M(m) ((attr_matcher_t *)(m)) + +/* match services */ +typedef struct { + obj_matcher_t super; + /* match by attributes assigned to the service */ + attr_matcher_t *attr; +} service_matcher_t; +#define SERVICE_M(m) ((service_matcher_t *)(m)) + +/* match hosts */ +typedef struct { + obj_matcher_t super; + /* match by services assigned to the host */ + service_matcher_t *service; + /* match by attributes assigned to the host */ + attr_matcher_t *attr; +} host_matcher_t; +#define HOST_M(m) ((host_matcher_t *)(m)) + +/* + * matcher implementations + */ + +static int +match_logical(matcher_t *m, sdb_store_base_t *obj); +static int +match_obj(matcher_t *m, sdb_store_base_t *obj); + +/* specific matchers */ + +static int +match_name(name_matcher_t *m, const char *name) +{ + assert(m); + + if ((! m->name) && (! m->name_re)) + return 0; + + if (! name) + name = ""; + + if (m->name && (! strcasecmp(m->name, name))) + return 0; + if (m->name_re && (! regexec(m->name_re, name, + /* matches */ 0, NULL, /* flags = */ 0))) + return 0; + return -1; +} /* match_name */ + +/* match attribute specific values; + * always call this function through match_obj() */ +static int +match_attr(attr_matcher_t *m, sdb_store_base_t *obj) +{ + assert(m && obj); + + if (obj->type != SDB_ATTRIBUTE) + return -1; + + { + sdb_attribute_t *attr = SDB_ATTR(obj); + char buf[sdb_data_strlen(&attr->value) + 1]; + + if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED)) + return -1; + return match_name(&m->value, buf); + } +} /* match_attr */ + +/* match service specific values; + * always call this function through match_obj() */ +static int +match_service(service_matcher_t *m, sdb_store_base_t *obj) +{ + sdb_llist_iter_t *iter; + + assert(m && obj); + + if (obj->type != SDB_SERVICE) + return -1; + + iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes); + while (sdb_llist_iter_has_next(iter)) { + sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter)); + + /* if any of the attributes matches we found a matching service */ + if (! match_obj(M(m->attr), attr)) { + sdb_llist_iter_destroy(iter); + return 0; + } + } + sdb_llist_iter_destroy(iter); + return -1; +} /* match_service */ + +/* match host specific values; + * always call this function through match_obj() */ +static int +match_host(host_matcher_t *m, sdb_store_base_t *obj) +{ + sdb_llist_iter_t *iter; + int status; + + assert(m && obj); + + if (obj->type != SDB_HOST) + return -1; + + if (m->service) { + iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->children); + status = -1; + } + else { + iter = NULL; + status = 0; + } + while (sdb_llist_iter_has_next(iter)) { + sdb_store_base_t *service = STORE_BASE(sdb_llist_iter_get_next(iter)); + + /* found a matching service */ + if (! match_obj(M(m->service), service)) { + status = 0; + break; + } + } + sdb_llist_iter_destroy(iter); + + if (status) + return status; + else if (! m->attr) + return 0; + + iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes); + while (sdb_llist_iter_has_next(iter)) { + sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter)); + + /* if any attribute matches, we found a matching host */ + if (! match_obj(M(m->attr), attr)) { + sdb_llist_iter_destroy(iter); + return 0; + } + } + sdb_llist_iter_destroy(iter); + return -1; +} /* match_host */ + +/* generic matchers */ + +enum { + MATCHER_OR, + MATCHER_AND, + MATCHER_ATTR, + MATCHER_SERVICE, + MATCHER_HOST, +}; + +typedef int (*matcher_cb)(matcher_t *, sdb_store_base_t *); + +/* this array needs to be indexable by the matcher types */ +static matcher_cb matchers[] = { + match_logical, + match_logical, + match_obj, + match_obj, + match_obj, +}; + +static int +match(matcher_t *m, sdb_store_base_t *obj) +{ + assert(m && obj); + assert((0 <= m->type) + && ((size_t)m->type < SDB_STATIC_ARRAY_LEN(matchers))); + + return matchers[m->type](m, obj); +} /* match */ + +static int +match_logical(matcher_t *m, sdb_store_base_t *obj) +{ + int status; + + assert(m && obj); + assert(OP_M(m)->left && OP_M(m)->right); + + status = match(OP_M(m)->left, obj); + /* lazy evaluation */ + if (status && (m->type == MATCHER_AND)) + return status; + else if ((! status) && (m->type == MATCHER_OR)) + return status; + + return match(OP_M(m)->right, obj); +} /* match_logical */ + +static int +match_obj(matcher_t *m, sdb_store_base_t *obj) +{ + int status; + + assert(m && obj); + + status = match_name(&OBJ_M(m)->name, obj->super.name); + if (status) + return status; + + switch (m->type) { + case MATCHER_ATTR: + return match_attr(ATTR_M(m), obj); + break; + case MATCHER_SERVICE: + return match_service(SERVICE_M(m), obj); + break; + case MATCHER_HOST: + return match_host(HOST_M(m), obj); + break; + } + return -1; +} /* match_obj */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + -- 2.30.2