26e466617dc29244da13a770dcc465554b5b68fd
1 /*
2 * SysDB - src/core/store_lookup.c
3 * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 /*
29 * This module implements operators which may be used to select contents of
30 * the store by matching various attributes of the stored objects. For now, a
31 * simple full table scan is supported only.
32 */
34 #include "sysdb.h"
35 #include "core/store-private.h"
37 #include <assert.h>
39 #include <sys/types.h>
40 #include <regex.h>
42 #include <string.h>
44 /*
45 * private data types
46 */
48 /* match the name of something */
49 typedef struct {
50 const char *name;
51 regex_t *name_re;
52 } name_matcher_t;
54 /* matcher base type */
55 typedef struct {
56 /* type of the matcher */
57 int type;
58 } matcher_t;
59 #define M(m) ((matcher_t *)(m))
61 /* logical operator matcher */
62 typedef struct {
63 matcher_t super;
65 /* left and right hand operands */
66 matcher_t *left;
67 matcher_t *right;
68 } op_matcher_t;
69 #define OP_M(m) ((op_matcher_t *)(m))
71 /* match any type of object by it's base information */
72 typedef struct {
73 matcher_t super;
75 /* match by the name of the object */
76 name_matcher_t name;
77 } obj_matcher_t;
78 #define OBJ_M(m) ((obj_matcher_t *)(m))
80 /* match attributes */
81 typedef struct {
82 obj_matcher_t super;
83 /* XXX: this needs to be more flexible;
84 * add support for type-specific operators */
85 name_matcher_t value;
86 } attr_matcher_t;
87 #define ATTR_M(m) ((attr_matcher_t *)(m))
89 /* match services */
90 typedef struct {
91 obj_matcher_t super;
92 /* match by attributes assigned to the service */
93 attr_matcher_t *attr;
94 } service_matcher_t;
95 #define SERVICE_M(m) ((service_matcher_t *)(m))
97 /* match hosts */
98 typedef struct {
99 obj_matcher_t super;
100 /* match by services assigned to the host */
101 service_matcher_t *service;
102 /* match by attributes assigned to the host */
103 attr_matcher_t *attr;
104 } host_matcher_t;
105 #define HOST_M(m) ((host_matcher_t *)(m))
107 /*
108 * matcher implementations
109 */
111 static int
112 match_logical(matcher_t *m, sdb_store_base_t *obj);
113 static int
114 match_obj(matcher_t *m, sdb_store_base_t *obj);
116 /* specific matchers */
118 static int
119 match_name(name_matcher_t *m, const char *name)
120 {
121 assert(m);
123 if ((! m->name) && (! m->name_re))
124 return 0;
126 if (! name)
127 name = "";
129 if (m->name && strcasecmp(m->name, name))
130 return -1;
131 if (m->name_re && regexec(m->name_re, name,
132 /* matches */ 0, NULL, /* flags = */ 0))
133 return -1;
134 return 0;
135 } /* match_name */
137 /* match attribute specific values;
138 * always call this function through match_obj() */
139 static int
140 match_attr(attr_matcher_t *m, sdb_store_base_t *obj)
141 {
142 assert(m && obj);
144 if (obj->type != SDB_ATTRIBUTE)
145 return -1;
147 {
148 sdb_attribute_t *attr = SDB_ATTR(obj);
149 char buf[sdb_data_strlen(&attr->value) + 1];
151 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
152 return -1;
153 return match_name(&m->value, buf);
154 }
155 } /* match_attr */
157 /* match service specific values;
158 * always call this function through match_obj() */
159 static int
160 match_service(service_matcher_t *m, sdb_store_base_t *obj)
161 {
162 sdb_llist_iter_t *iter;
164 assert(m && obj);
166 if (obj->type != SDB_SERVICE)
167 return -1;
169 iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes);
170 while (sdb_llist_iter_has_next(iter)) {
171 sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter));
173 /* if any of the attributes matches we found a matching service */
174 if (! match_obj(M(m->attr), attr)) {
175 sdb_llist_iter_destroy(iter);
176 return 0;
177 }
178 }
179 sdb_llist_iter_destroy(iter);
180 return -1;
181 } /* match_service */
183 /* match host specific values;
184 * always call this function through match_obj() */
185 static int
186 match_host(host_matcher_t *m, sdb_store_base_t *obj)
187 {
188 sdb_llist_iter_t *iter;
189 int status;
191 assert(m && obj);
193 if (obj->type != SDB_HOST)
194 return -1;
196 if (m->service) {
197 iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->children);
198 status = -1;
199 }
200 else {
201 iter = NULL;
202 status = 0;
203 }
204 while (sdb_llist_iter_has_next(iter)) {
205 sdb_store_base_t *service = STORE_BASE(sdb_llist_iter_get_next(iter));
207 /* found a matching service */
208 if (! match_obj(M(m->service), service)) {
209 status = 0;
210 break;
211 }
212 }
213 sdb_llist_iter_destroy(iter);
215 if (status)
216 return status;
217 else if (! m->attr)
218 return 0;
220 iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes);
221 while (sdb_llist_iter_has_next(iter)) {
222 sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter));
224 /* if any attribute matches, we found a matching host */
225 if (! match_obj(M(m->attr), attr)) {
226 sdb_llist_iter_destroy(iter);
227 return 0;
228 }
229 }
230 sdb_llist_iter_destroy(iter);
231 return -1;
232 } /* match_host */
234 /* generic matchers */
236 enum {
237 MATCHER_OR,
238 MATCHER_AND,
239 MATCHER_ATTR,
240 MATCHER_SERVICE,
241 MATCHER_HOST,
242 };
244 typedef int (*matcher_cb)(matcher_t *, sdb_store_base_t *);
246 /* this array needs to be indexable by the matcher types */
247 static matcher_cb matchers[] = {
248 match_logical,
249 match_logical,
250 match_obj,
251 match_obj,
252 match_obj,
253 };
255 static int
256 match(matcher_t *m, sdb_store_base_t *obj)
257 {
258 assert(m && obj);
259 assert((0 <= m->type)
260 && ((size_t)m->type < SDB_STATIC_ARRAY_LEN(matchers)));
262 return matchers[m->type](m, obj);
263 } /* match */
265 static int
266 match_logical(matcher_t *m, sdb_store_base_t *obj)
267 {
268 int status;
270 assert(m && obj);
271 assert(OP_M(m)->left && OP_M(m)->right);
273 status = match(OP_M(m)->left, obj);
274 /* lazy evaluation */
275 if (status && (m->type == MATCHER_AND))
276 return status;
277 else if ((! status) && (m->type == MATCHER_OR))
278 return status;
280 return match(OP_M(m)->right, obj);
281 } /* match_logical */
283 static int
284 match_obj(matcher_t *m, sdb_store_base_t *obj)
285 {
286 int status;
288 assert(m && obj);
290 status = match_name(&OBJ_M(m)->name, obj->super.name);
291 if (status)
292 return status;
294 switch (m->type) {
295 case MATCHER_ATTR:
296 return match_attr(ATTR_M(m), obj);
297 break;
298 case MATCHER_SERVICE:
299 return match_service(SERVICE_M(m), obj);
300 break;
301 case MATCHER_HOST:
302 return match_host(HOST_M(m), obj);
303 break;
304 }
305 return -1;
306 } /* match_obj */
308 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */