Code

Include config.h in source files.
[sysdb.git] / src / core / store_lookup.c
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 #if HAVE_CONFIG_H
35 #       include "config.h"
36 #endif /* HAVE_CONFIG_H */
38 #include "sysdb.h"
39 #include "core/store-private.h"
40 #include "core/object.h"
42 #include <assert.h>
44 #include <sys/types.h>
45 #include <regex.h>
47 #include <stdlib.h>
48 #include <string.h>
50 /*
51  * private data types
52  */
54 /* match the name of something */
55 typedef struct {
56         char    *name;
57         regex_t *name_re;
58 } name_matcher_t;
60 /* matcher base type */
61 struct sdb_store_matcher {
62         sdb_object_t super;
63         /* type of the matcher */
64         int type;
65 };
66 #define M(m) ((sdb_store_matcher_t *)(m))
68 /* logical operator matcher */
69 typedef struct {
70         sdb_store_matcher_t super;
72         /* left and right hand operands */
73         sdb_store_matcher_t *left;
74         sdb_store_matcher_t *right;
75 } op_matcher_t;
76 #define OP_M(m) ((op_matcher_t *)(m))
78 /* match any type of object by it's base information */
79 typedef struct {
80         sdb_store_matcher_t super;
82         /* match by the name of the object */
83         name_matcher_t name;
84 } obj_matcher_t;
85 #define OBJ_M(m) ((obj_matcher_t *)(m))
87 /* match attributes */
88 typedef struct {
89         obj_matcher_t super;
90         /* XXX: this needs to be more flexible;
91          *      add support for type-specific operators */
92         name_matcher_t value;
93 } attr_matcher_t;
94 #define ATTR_M(m) ((attr_matcher_t *)(m))
96 /* match services */
97 typedef struct {
98         obj_matcher_t super;
99         /* match by attributes assigned to the service */
100         attr_matcher_t *attr;
101 } service_matcher_t;
102 #define SERVICE_M(m) ((service_matcher_t *)(m))
104 /* match hosts */
105 typedef struct {
106         obj_matcher_t super;
107         /* match by services assigned to the host */
108         service_matcher_t *service;
109         /* match by attributes assigned to the host */
110         attr_matcher_t *attr;
111 } host_matcher_t;
112 #define HOST_M(m) ((host_matcher_t *)(m))
114 /*
115  * matcher implementations
116  */
118 static int
119 match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj);
120 static int
121 match_obj(sdb_store_matcher_t *m, sdb_store_base_t *obj);
123 /* specific matchers */
125 static int
126 match_name(name_matcher_t *m, const char *name)
128         assert(m);
130         if ((! m->name) && (! m->name_re))
131                 return 0;
133         if (! name)
134                 name = "";
136         if (m->name && strcasecmp(m->name, name))
137                 return -1;
138         if (m->name_re && regexec(m->name_re, name,
139                                         /* matches */ 0, NULL, /* flags = */ 0))
140                 return -1;
141         return 0;
142 } /* match_name */
144 /* match attribute specific values;
145  * always call this function through match_obj() */
146 static int
147 match_attr(attr_matcher_t *m, sdb_store_base_t *obj)
149         assert(m && obj);
151         if (obj->type != SDB_ATTRIBUTE)
152                 return -1;
154         {
155                 sdb_attribute_t *attr = SDB_ATTR(obj);
156                 char buf[sdb_data_strlen(&attr->value) + 1];
158                 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
159                         return -1;
160                 return match_name(&m->value, buf);
161         }
162 } /* match_attr */
164 /* match service specific values;
165  * always call this function through match_obj() */
166 static int
167 match_service(service_matcher_t *m, sdb_store_base_t *obj)
169         sdb_llist_iter_t *iter;
171         assert(m && obj);
173         if (obj->type != SDB_SERVICE)
174                 return -1;
176         if (! m->attr)
177                 return 0;
179         iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes);
180         while (sdb_llist_iter_has_next(iter)) {
181                 sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter));
183                 /* if any of the attributes matches we found a matching service */
184                 if (! match_obj(M(m->attr), attr)) {
185                         sdb_llist_iter_destroy(iter);
186                         return 0;
187                 }
188         }
189         sdb_llist_iter_destroy(iter);
190         return -1;
191 } /* match_service */
193 /* match host specific values;
194  * always call this function through match_obj() */
195 static int
196 match_host(host_matcher_t *m, sdb_store_base_t *obj)
198         sdb_llist_iter_t *iter;
199         int status;
201         assert(m && obj);
203         if (obj->type != SDB_HOST)
204                 return -1;
206         if (m->service) {
207                 iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->children);
208                 status = -1;
209         }
210         else {
211                 iter = NULL;
212                 status = 0;
213         }
214         while (sdb_llist_iter_has_next(iter)) {
215                 sdb_store_base_t *service = STORE_BASE(sdb_llist_iter_get_next(iter));
217                 /* found a matching service */
218                 if (! match_obj(M(m->service), service)) {
219                         status = 0;
220                         break;
221                 }
222         }
223         sdb_llist_iter_destroy(iter);
225         if (status)
226                 return status;
227         else if (! m->attr)
228                 return 0;
230         iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes);
231         while (sdb_llist_iter_has_next(iter)) {
232                 sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter));
234                 /* if any attribute matches, we found a matching host */
235                 if (! match_obj(M(m->attr), attr)) {
236                         sdb_llist_iter_destroy(iter);
237                         return 0;
238                 }
239         }
240         sdb_llist_iter_destroy(iter);
241         return -1;
242 } /* match_host */
244 /* generic matchers */
246 enum {
247         MATCHER_OR,
248         MATCHER_AND,
249         MATCHER_ATTR,
250         MATCHER_SERVICE,
251         MATCHER_HOST,
252 };
254 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_base_t *);
256 /* this array needs to be indexable by the matcher types */
257 static matcher_cb matchers[] = {
258         match_logical,
259         match_logical,
260         match_obj,
261         match_obj,
262         match_obj,
263 };
265 static int
266 match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj)
268         int status;
270         assert(m && obj);
271         assert(OP_M(m)->left && OP_M(m)->right);
273         status = sdb_store_matcher_matches(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 sdb_store_matcher_matches(OP_M(m)->right, obj);
281 } /* match_logical */
283 static int
284 match_obj(sdb_store_matcher_t *m, sdb_store_base_t *obj)
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 /*
309  * private matcher types
310  */
312 /* initializes a name matcher consuming two elements from ap */
313 static int
314 name_matcher_init(name_matcher_t *m, va_list ap)
316         const char *name = va_arg(ap, const char *);
317         const char *name_re = va_arg(ap, const char *);
319         if (name) {
320                 m->name = strdup(name);
321                 if (! m->name)
322                         return -1;
323         }
324         if (name_re) {
325                 m->name_re = malloc(sizeof(*m->name_re));
326                 if (! m->name_re)
327                         return -1;
328                 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
329                         return -1;
330         }
331         return 0;
332 } /* name_matcher_init */
334 static void
335 name_matcher_destroy(name_matcher_t *m)
337         if (m->name)
338                 free(m->name);
339         if (m->name_re) {
340                 regfree(m->name_re);
341                 free(m->name_re);
342         }
343 } /* name_matcher_destroy */
345 /* initializes an object matcher consuming two elements from ap */
346 static int
347 obj_matcher_init(sdb_object_t *obj, va_list ap)
349         obj_matcher_t *m = OBJ_M(obj);
350         return name_matcher_init(&m->name, ap);
351 } /* obj_matcher_init */
353 static void
354 obj_matcher_destroy(sdb_object_t *obj)
356         obj_matcher_t *m = OBJ_M(obj);
357         name_matcher_destroy(&m->name);
358 } /* obj_matcher_destroy */
360 static int
361 attr_matcher_init(sdb_object_t *obj, va_list ap)
363         attr_matcher_t *attr = ATTR_M(obj);
364         int status;
366         M(obj)->type = MATCHER_ATTR;
368         status = obj_matcher_init(obj, ap);
369         if (! status)
370                 status = name_matcher_init(&attr->value, ap);
371         return status;
372 } /* attr_matcher_init */
374 static void
375 attr_matcher_destroy(sdb_object_t *obj)
377         attr_matcher_t *attr = ATTR_M(obj);
379         obj_matcher_destroy(obj);
380         name_matcher_destroy(&attr->value);
381 } /* attr_matcher_destroy */
383 static int
384 service_matcher_init(sdb_object_t *obj, va_list ap)
386         attr_matcher_t *attr;
387         int status;
389         M(obj)->type = MATCHER_SERVICE;
391         status = obj_matcher_init(obj, ap);
392         if (status)
393                 return status;
395         attr = va_arg(ap, attr_matcher_t *);
397         sdb_object_ref(SDB_OBJ(attr));
398         SERVICE_M(obj)->attr = attr;
399         return 0;
400 } /* service_matcher_init */
402 static void
403 service_matcher_destroy(sdb_object_t *obj)
405         obj_matcher_destroy(obj);
406         sdb_object_deref(SDB_OBJ(SERVICE_M(obj)->attr));
407 } /* service_matcher_destroy */
409 static int
410 host_matcher_init(sdb_object_t *obj, va_list ap)
412         service_matcher_t *service;
413         attr_matcher_t *attr;
414         int status;
416         M(obj)->type = MATCHER_HOST;
418         status = obj_matcher_init(obj, ap);
419         if (status)
420                 return status;
422         service = va_arg(ap, service_matcher_t *);
423         attr = va_arg(ap, attr_matcher_t *);
425         sdb_object_ref(SDB_OBJ(service));
426         HOST_M(obj)->service = service;
427         sdb_object_ref(SDB_OBJ(attr));
428         HOST_M(obj)->attr = attr;
429         return 0;
430 } /* host_matcher_init */
432 static void
433 host_matcher_destroy(sdb_object_t *obj)
435         obj_matcher_destroy(obj);
436         sdb_object_deref(SDB_OBJ(HOST_M(obj)->service));
437         sdb_object_deref(SDB_OBJ(HOST_M(obj)->attr));
438 } /* host_matcher_destroy */
440 static int
441 op_matcher_init(sdb_object_t *obj, va_list ap)
443         M(obj)->type = va_arg(ap, int);
444         if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
445                 return -1;
447         OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
448         sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
449         OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
450         sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
452         if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
453                 return -1;
454         return 0;
455 } /* op_matcher_init */
457 static void
458 op_matcher_destroy(sdb_object_t *obj)
460         if (OP_M(obj)->left)
461                 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
462         if (OP_M(obj)->right)
463                 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
464 } /* op_matcher_destroy */
466 static sdb_type_t attr_type = {
467         /* size = */ sizeof(attr_matcher_t),
468         /* init = */ attr_matcher_init,
469         /* destroy = */ attr_matcher_destroy,
470 };
472 static sdb_type_t service_type = {
473         /* size = */ sizeof(service_matcher_t),
474         /* init = */ service_matcher_init,
475         /* destroy = */ service_matcher_destroy,
476 };
478 static sdb_type_t host_type = {
479         /* size = */ sizeof(host_matcher_t),
480         /* init = */ host_matcher_init,
481         /* destroy = */ host_matcher_destroy,
482 };
484 static sdb_type_t op_type = {
485         /* size = */ sizeof(op_matcher_t),
486         /* init = */ op_matcher_init,
487         /* destroy = */ op_matcher_destroy,
488 };
490 /*
491  * public API
492  */
494 sdb_store_matcher_t *
495 sdb_store_attr_matcher(const char *attr_name, const char *attr_name_re,
496                 const char *attr_value, const char *attr_value_re)
498         return M(sdb_object_create("attr-matcher", attr_type,
499                                 attr_name, attr_name_re, attr_value, attr_value_re));
500 } /* sdb_store_attr_matcher */
502 sdb_store_matcher_t *
503 sdb_store_service_matcher(const char *service_name, const char *service_name_re,
504                 sdb_store_matcher_t *attr_matcher)
506         return M(sdb_object_create("service-matcher", service_type,
507                                 service_name, service_name_re, attr_matcher));
508 } /* sdb_store_service_matcher */
510 sdb_store_matcher_t *
511 sdb_store_host_matcher(const char *host_name, const char *host_name_re,
512                 sdb_store_matcher_t *service_matcher,
513                 sdb_store_matcher_t *attr_matcher)
515         return M(sdb_object_create("host-matcher", host_type,
516                                 host_name, host_name_re, service_matcher, attr_matcher));
517 } /* sdb_store_host_matcher */
519 sdb_store_matcher_t *
520 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
522         return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
523                                 left, right));
524 } /* sdb_store_dis_matcher */
526 sdb_store_matcher_t *
527 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
529         return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
530                                 left, right));
531 } /* sdb_store_con_matcher */
533 int
534 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj)
536         /* "NULL" always matches */
537         if ((! m) || (! obj))
538                 return 0;
540         if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
541                 return -1;
543         return matchers[m->type](m, obj);
544 } /* sdb_store_matcher_matches */
546 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */