Code

store: Moved matcher types to store-private.h.
[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 typedef struct {
55         sdb_store_matcher_t *m;
56         sdb_store_lookup_cb  cb;
57         void *user_data;
58 } lookup_iter_data_t;
60 /*
61  * private helper functions
62  */
64 static int
65 lookup_iter(sdb_store_base_t *obj, void *user_data)
66 {
67         lookup_iter_data_t *d = user_data;
69         if (sdb_store_matcher_matches(d->m, obj))
70                 return d->cb(obj, d->user_data);
71         return 0;
72 } /* lookup_iter */
74 /*
75  * matcher implementations
76  */
78 static int
79 match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj);
80 static int
81 match_obj(sdb_store_matcher_t *m, sdb_store_base_t *obj);
83 /* specific matchers */
85 static int
86 match_name(name_matcher_t *m, const char *name)
87 {
88         assert(m);
90         if ((! m->name) && (! m->name_re))
91                 return 1;
93         if (! name)
94                 name = "";
96         if (m->name && strcasecmp(m->name, name))
97                 return 0;
98         if (m->name_re && regexec(m->name_re, name,
99                                         /* matches */ 0, NULL, /* flags = */ 0))
100                 return 0;
101         return 1;
102 } /* match_name */
104 /* match attribute specific values;
105  * always call this function through match_obj() */
106 static int
107 match_attr(attr_matcher_t *m, sdb_store_base_t *obj)
109         assert(m && obj);
111         if (obj->type != SDB_ATTRIBUTE)
112                 return 0;
114         {
115                 sdb_attribute_t *attr = SDB_ATTR(obj);
116                 char buf[sdb_data_strlen(&attr->value) + 1];
118                 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
119                         return 0;
120                 return match_name(&m->value, buf);
121         }
122 } /* match_attr */
124 /* match service specific values;
125  * always call this function through match_obj() */
126 static int
127 match_service(service_matcher_t *m, sdb_store_base_t *obj)
129         sdb_llist_iter_t *iter;
131         assert(m && obj);
133         if (obj->type != SDB_SERVICE)
134                 return 0;
136         if (! m->attr)
137                 return 1;
139         iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes);
140         while (sdb_llist_iter_has_next(iter)) {
141                 sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter));
143                 /* if any of the attributes matches we found a matching service */
144                 if (match_obj(M(m->attr), attr)) {
145                         sdb_llist_iter_destroy(iter);
146                         return 1;
147                 }
148         }
149         sdb_llist_iter_destroy(iter);
150         return 0;
151 } /* match_service */
153 /* match host specific values;
154  * always call this function through match_obj() */
155 static int
156 match_host(host_matcher_t *m, sdb_store_base_t *obj)
158         sdb_llist_iter_t *iter;
159         int status;
161         assert(m && obj);
163         if (obj->type != SDB_HOST)
164                 return 0;
166         if (m->service) {
167                 iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->children);
168                 status = 0;
169         }
170         else {
171                 iter = NULL;
172                 status = 1;
173         }
174         while (sdb_llist_iter_has_next(iter)) {
175                 sdb_store_base_t *service = STORE_BASE(sdb_llist_iter_get_next(iter));
177                 /* found a matching service */
178                 if (match_obj(M(m->service), service)) {
179                         status = 1;
180                         break;
181                 }
182         }
183         sdb_llist_iter_destroy(iter);
185         if (! status)
186                 return status;
187         else if (! m->attr)
188                 return 1;
190         iter = sdb_llist_get_iter(SDB_STORE_OBJ(obj)->attributes);
191         while (sdb_llist_iter_has_next(iter)) {
192                 sdb_store_base_t *attr = STORE_BASE(sdb_llist_iter_get_next(iter));
194                 /* if any attribute matches, we found a matching host */
195                 if (match_obj(M(m->attr), attr)) {
196                         sdb_llist_iter_destroy(iter);
197                         return 1;
198                 }
199         }
200         sdb_llist_iter_destroy(iter);
201         return 0;
202 } /* match_host */
204 /* generic matchers */
206 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_base_t *);
208 /* this array needs to be indexable by the matcher types;
209  * -> update the enum in store-private.h when updating this */
210 static matcher_cb matchers[] = {
211         match_logical,
212         match_logical,
213         match_obj,
214         match_obj,
215         match_obj,
216 };
218 static int
219 match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj)
221         int status;
223         assert(m && obj);
224         assert(OP_M(m)->left && OP_M(m)->right);
226         status = sdb_store_matcher_matches(OP_M(m)->left, obj);
227         /* lazy evaluation */
228         if ((! status) && (m->type == MATCHER_AND))
229                 return status;
230         else if (status && (m->type == MATCHER_OR))
231                 return status;
233         return sdb_store_matcher_matches(OP_M(m)->right, obj);
234 } /* match_logical */
236 static int
237 match_obj(sdb_store_matcher_t *m, sdb_store_base_t *obj)
239         int status;
241         assert(m && obj);
243         status = match_name(&OBJ_M(m)->name, obj->super.name);
244         if (! status)
245                 return status;
247         switch (m->type) {
248                 case MATCHER_ATTR:
249                         return match_attr(ATTR_M(m), obj);
250                         break;
251                 case MATCHER_SERVICE:
252                         return match_service(SERVICE_M(m), obj);
253                         break;
254                 case MATCHER_HOST:
255                         return match_host(HOST_M(m), obj);
256                         break;
257         }
258         return 0;
259 } /* match_obj */
261 /*
262  * private matcher types
263  */
265 /* initializes a name matcher consuming two elements from ap */
266 static int
267 name_matcher_init(name_matcher_t *m, va_list ap)
269         const char *name = va_arg(ap, const char *);
270         const char *name_re = va_arg(ap, const char *);
272         if (name) {
273                 m->name = strdup(name);
274                 if (! m->name)
275                         return -1;
276         }
277         if (name_re) {
278                 m->name_re = malloc(sizeof(*m->name_re));
279                 if (! m->name_re)
280                         return -1;
281                 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
282                         return -1;
283         }
284         return 0;
285 } /* name_matcher_init */
287 static void
288 name_matcher_destroy(name_matcher_t *m)
290         if (m->name)
291                 free(m->name);
292         if (m->name_re) {
293                 regfree(m->name_re);
294                 free(m->name_re);
295         }
296 } /* name_matcher_destroy */
298 /* initializes an object matcher consuming two elements from ap */
299 static int
300 obj_matcher_init(sdb_object_t *obj, va_list ap)
302         obj_matcher_t *m = OBJ_M(obj);
303         return name_matcher_init(&m->name, ap);
304 } /* obj_matcher_init */
306 static void
307 obj_matcher_destroy(sdb_object_t *obj)
309         obj_matcher_t *m = OBJ_M(obj);
310         name_matcher_destroy(&m->name);
311 } /* obj_matcher_destroy */
313 static int
314 attr_matcher_init(sdb_object_t *obj, va_list ap)
316         attr_matcher_t *attr = ATTR_M(obj);
317         int status;
319         M(obj)->type = MATCHER_ATTR;
321         status = obj_matcher_init(obj, ap);
322         if (! status)
323                 status = name_matcher_init(&attr->value, ap);
324         return status;
325 } /* attr_matcher_init */
327 static void
328 attr_matcher_destroy(sdb_object_t *obj)
330         attr_matcher_t *attr = ATTR_M(obj);
332         obj_matcher_destroy(obj);
333         name_matcher_destroy(&attr->value);
334 } /* attr_matcher_destroy */
336 static int
337 service_matcher_init(sdb_object_t *obj, va_list ap)
339         attr_matcher_t *attr;
340         int status;
342         M(obj)->type = MATCHER_SERVICE;
344         status = obj_matcher_init(obj, ap);
345         if (status)
346                 return status;
348         attr = va_arg(ap, attr_matcher_t *);
350         sdb_object_ref(SDB_OBJ(attr));
351         SERVICE_M(obj)->attr = attr;
352         return 0;
353 } /* service_matcher_init */
355 static void
356 service_matcher_destroy(sdb_object_t *obj)
358         obj_matcher_destroy(obj);
359         sdb_object_deref(SDB_OBJ(SERVICE_M(obj)->attr));
360 } /* service_matcher_destroy */
362 static int
363 host_matcher_init(sdb_object_t *obj, va_list ap)
365         service_matcher_t *service;
366         attr_matcher_t *attr;
367         int status;
369         M(obj)->type = MATCHER_HOST;
371         status = obj_matcher_init(obj, ap);
372         if (status)
373                 return status;
375         service = va_arg(ap, service_matcher_t *);
376         attr = va_arg(ap, attr_matcher_t *);
378         sdb_object_ref(SDB_OBJ(service));
379         HOST_M(obj)->service = service;
380         sdb_object_ref(SDB_OBJ(attr));
381         HOST_M(obj)->attr = attr;
382         return 0;
383 } /* host_matcher_init */
385 static void
386 host_matcher_destroy(sdb_object_t *obj)
388         obj_matcher_destroy(obj);
389         sdb_object_deref(SDB_OBJ(HOST_M(obj)->service));
390         sdb_object_deref(SDB_OBJ(HOST_M(obj)->attr));
391 } /* host_matcher_destroy */
393 static int
394 op_matcher_init(sdb_object_t *obj, va_list ap)
396         M(obj)->type = va_arg(ap, int);
397         if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
398                 return -1;
400         OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
401         sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
402         OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
403         sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
405         if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
406                 return -1;
407         return 0;
408 } /* op_matcher_init */
410 static void
411 op_matcher_destroy(sdb_object_t *obj)
413         if (OP_M(obj)->left)
414                 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
415         if (OP_M(obj)->right)
416                 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
417 } /* op_matcher_destroy */
419 static sdb_type_t attr_type = {
420         /* size = */ sizeof(attr_matcher_t),
421         /* init = */ attr_matcher_init,
422         /* destroy = */ attr_matcher_destroy,
423 };
425 static sdb_type_t service_type = {
426         /* size = */ sizeof(service_matcher_t),
427         /* init = */ service_matcher_init,
428         /* destroy = */ service_matcher_destroy,
429 };
431 static sdb_type_t host_type = {
432         /* size = */ sizeof(host_matcher_t),
433         /* init = */ host_matcher_init,
434         /* destroy = */ host_matcher_destroy,
435 };
437 static sdb_type_t op_type = {
438         /* size = */ sizeof(op_matcher_t),
439         /* init = */ op_matcher_init,
440         /* destroy = */ op_matcher_destroy,
441 };
443 /*
444  * public API
445  */
447 sdb_store_matcher_t *
448 sdb_store_attr_matcher(const char *attr_name, const char *attr_name_re,
449                 const char *attr_value, const char *attr_value_re)
451         return M(sdb_object_create("attr-matcher", attr_type,
452                                 attr_name, attr_name_re, attr_value, attr_value_re));
453 } /* sdb_store_attr_matcher */
455 sdb_store_matcher_t *
456 sdb_store_service_matcher(const char *service_name, const char *service_name_re,
457                 sdb_store_matcher_t *attr_matcher)
459         return M(sdb_object_create("service-matcher", service_type,
460                                 service_name, service_name_re, attr_matcher));
461 } /* sdb_store_service_matcher */
463 sdb_store_matcher_t *
464 sdb_store_host_matcher(const char *host_name, const char *host_name_re,
465                 sdb_store_matcher_t *service_matcher,
466                 sdb_store_matcher_t *attr_matcher)
468         return M(sdb_object_create("host-matcher", host_type,
469                                 host_name, host_name_re, service_matcher, attr_matcher));
470 } /* sdb_store_host_matcher */
472 sdb_store_matcher_t *
473 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
475         return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
476                                 left, right));
477 } /* sdb_store_dis_matcher */
479 sdb_store_matcher_t *
480 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
482         return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
483                                 left, right));
484 } /* sdb_store_con_matcher */
486 int
487 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj)
489         /* "NULL" always matches */
490         if ((! m) || (! obj))
491                 return 1;
493         if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
494                 return 0;
496         return matchers[m->type](m, obj);
497 } /* sdb_store_matcher_matches */
499 int
500 sdb_store_lookup(sdb_store_matcher_t *m, sdb_store_lookup_cb cb,
501                 void *user_data)
503         lookup_iter_data_t data = { m, cb, user_data };
505         if (! cb)
506                 return -1;
507         return sdb_store_iterate(lookup_iter, &data);
508 } /* sdb_store_lookup */
510 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */