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 #include <limits.h>
52 /*
53 * private data types
54 */
56 typedef struct {
57 sdb_store_matcher_t *m;
58 sdb_store_lookup_cb cb;
59 void *user_data;
60 } scan_iter_data_t;
62 /*
63 * private helper functions
64 */
66 static int
67 scan_iter(sdb_store_obj_t *obj, void *user_data)
68 {
69 scan_iter_data_t *d = user_data;
71 if (sdb_store_matcher_matches(d->m, obj))
72 return d->cb(obj, d->user_data);
73 return 0;
74 } /* scan_iter */
76 static sdb_attribute_t *
77 attr_get(sdb_host_t *host, const char *name)
78 {
79 sdb_avltree_iter_t *iter = NULL;
80 sdb_attribute_t *attr = NULL;
82 iter = sdb_avltree_get_iter(host->attributes);
83 while (sdb_avltree_iter_has_next(iter)) {
84 sdb_attribute_t *a = ATTR(sdb_avltree_iter_get_next(iter));
86 if (strcasecmp(name, SDB_OBJ(a)->name))
87 continue;
89 assert(STORE_OBJ(a)->type == SDB_ATTRIBUTE);
90 attr = a;
91 break;
92 }
93 sdb_avltree_iter_destroy(iter);
94 return attr;
95 } /* attr_get */
97 /*
98 * conditional implementations
99 */
101 static int
102 attr_cmp(sdb_host_t *host, sdb_store_cond_t *cond)
103 {
104 sdb_attribute_t *attr;
105 sdb_data_t value = SDB_DATA_INIT;
106 int status;
108 if (sdb_store_expr_eval(ATTR_C(cond)->expr, &value))
109 return INT_MAX;
111 attr = attr_get(host, ATTR_C(cond)->name);
112 if (! attr)
113 status = INT_MAX;
114 else if (attr->value.type != value.type)
115 status = INT_MAX;
116 else
117 status = sdb_data_cmp(&attr->value, &value);
118 sdb_data_free_datum(&value);
119 return status;
120 } /* attr_cmp */
122 /*
123 * matcher implementations
124 */
126 static int
127 match_string(string_matcher_t *m, const char *name)
128 {
129 if ((! m->name) && (! m->name_re))
130 return 1;
132 if (! name)
133 name = "";
135 if (m->name && strcasecmp(m->name, name))
136 return 0;
137 if (m->name_re && regexec(m->name_re, name,
138 /* matches */ 0, NULL, /* flags = */ 0))
139 return 0;
140 return 1;
141 } /* match_string */
143 static int
144 match_logical(sdb_store_matcher_t *m, sdb_host_t *host)
145 {
146 int status;
148 assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
149 assert(OP_M(m)->left && OP_M(m)->right);
151 status = sdb_store_matcher_matches(OP_M(m)->left, STORE_OBJ(host));
152 /* lazy evaluation */
153 if ((! status) && (m->type == MATCHER_AND))
154 return status;
155 else if (status && (m->type == MATCHER_OR))
156 return status;
158 return sdb_store_matcher_matches(OP_M(m)->right, STORE_OBJ(host));
159 } /* match_logical */
161 static int
162 match_unary(sdb_store_matcher_t *m, sdb_host_t *host)
163 {
164 assert(m->type == MATCHER_NOT);
165 assert(UOP_M(m)->op);
167 return !sdb_store_matcher_matches(UOP_M(m)->op, STORE_OBJ(host));
168 } /* match_unary */
170 static int
171 match_name(sdb_store_matcher_t *m, sdb_host_t *host)
172 {
173 sdb_avltree_iter_t *iter = NULL;
174 int status = 0;
176 assert(m->type == MATCHER_NAME);
178 switch (NAME_M(m)->obj_type) {
179 case SDB_HOST:
180 return match_string(&NAME_M(m)->name, SDB_OBJ(host)->name);
181 break;
182 case SDB_SERVICE:
183 iter = sdb_avltree_get_iter(host->services);
184 break;
185 case SDB_ATTRIBUTE:
186 iter = sdb_avltree_get_iter(host->attributes);
187 break;
188 }
190 while (sdb_avltree_iter_has_next(iter)) {
191 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
192 if (match_string(&NAME_M(m)->name, child->name)) {
193 status = 1;
194 break;
195 }
196 }
197 sdb_avltree_iter_destroy(iter);
198 return status;
199 } /* match_name */
201 static int
202 match_attr(sdb_store_matcher_t *m, sdb_host_t *host)
203 {
204 sdb_attribute_t *attr;
206 assert(m->type == MATCHER_ATTR);
207 assert(ATTR_M(m)->name);
209 attr = attr_get(host, ATTR_M(m)->name);
210 if (attr) {
211 char buf[sdb_data_strlen(&attr->value) + 1];
212 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
213 return 0;
214 if (match_string(&ATTR_M(m)->value, buf))
215 return 1;
216 }
217 return 0;
218 } /* match_attr */
220 static int
221 match_lt(sdb_store_matcher_t *m, sdb_host_t *host)
222 {
223 int status;
224 assert(m->type == MATCHER_LT);
225 status = COND_M(m)->cond->cmp(host, COND_M(m)->cond);
226 return (status != INT_MAX) && (status < 0);
227 } /* match_lt */
229 static int
230 match_le(sdb_store_matcher_t *m, sdb_host_t *host)
231 {
232 int status;
233 assert(m->type == MATCHER_LE);
234 status = COND_M(m)->cond->cmp(host, COND_M(m)->cond);
235 return (status != INT_MAX) && (status <= 0);
236 } /* match_le */
238 static int
239 match_eq(sdb_store_matcher_t *m, sdb_host_t *host)
240 {
241 int status;
242 assert(m->type == MATCHER_EQ);
243 status = COND_M(m)->cond->cmp(host, COND_M(m)->cond);
244 return (status != INT_MAX) && (! status);
245 } /* match_eq */
247 static int
248 match_ge(sdb_store_matcher_t *m, sdb_host_t *host)
249 {
250 int status;
251 assert(m->type == MATCHER_GE);
252 status = COND_M(m)->cond->cmp(host, COND_M(m)->cond);
253 return (status != INT_MAX) && (status >= 0);
254 } /* match_ge */
256 static int
257 match_gt(sdb_store_matcher_t *m, sdb_host_t *host)
258 {
259 int status;
260 assert(m->type == MATCHER_GT);
261 status = COND_M(m)->cond->cmp(host, COND_M(m)->cond);
262 return (status != INT_MAX) && (status > 0);
263 } /* match_gt */
265 static int
266 match_isnull(sdb_store_matcher_t *m, sdb_host_t *host)
267 {
268 assert(m->type == MATCHER_ISNULL);
269 return attr_get(host, ISNULL_M(m)->attr_name) == NULL;
270 } /* match_isnull */
272 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_host_t *);
274 /* this array needs to be indexable by the matcher types;
275 * -> update the enum in store-private.h when updating this */
276 static matcher_cb
277 matchers[] = {
278 match_logical,
279 match_logical,
280 match_unary,
281 match_name,
282 match_attr,
283 match_lt,
284 match_le,
285 match_eq,
286 match_ge,
287 match_gt,
288 match_isnull,
289 };
291 /*
292 * private conditional types
293 */
295 static int
296 attr_cond_init(sdb_object_t *obj, va_list ap)
297 {
298 const char *name = va_arg(ap, const char *);
299 sdb_store_expr_t *expr = va_arg(ap, sdb_store_expr_t *);
301 if (! name)
302 return -1;
304 SDB_STORE_COND(obj)->cmp = attr_cmp;
306 ATTR_C(obj)->name = strdup(name);
307 if (! ATTR_C(obj)->name)
308 return -1;
309 ATTR_C(obj)->expr = expr;
310 sdb_object_ref(SDB_OBJ(expr));
311 return 0;
312 } /* attr_cond_init */
314 static void
315 attr_cond_destroy(sdb_object_t *obj)
316 {
317 if (ATTR_C(obj)->name)
318 free(ATTR_C(obj)->name);
319 sdb_object_deref(SDB_OBJ(ATTR_C(obj)->expr));
320 } /* attr_cond_destroy */
322 static sdb_type_t attr_cond_type = {
323 /* size = */ sizeof(attr_cond_t),
324 /* init = */ attr_cond_init,
325 /* destroy = */ attr_cond_destroy,
326 };
328 /*
329 * private matcher types
330 */
332 /* initializes a string matcher consuming two elements from ap */
333 static int
334 string_matcher_init(string_matcher_t *m, va_list ap)
335 {
336 const char *name = va_arg(ap, const char *);
337 const char *name_re = va_arg(ap, const char *);
339 if (name) {
340 m->name = strdup(name);
341 if (! m->name)
342 return -1;
343 }
344 if (name_re) {
345 m->name_re = malloc(sizeof(*m->name_re));
346 if (! m->name_re)
347 return -1;
348 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
349 return -1;
350 }
351 return 0;
352 } /* string_matcher_init */
354 static void
355 string_matcher_destroy(string_matcher_t *m)
356 {
357 if (m->name)
358 free(m->name);
359 if (m->name_re) {
360 regfree(m->name_re);
361 free(m->name_re);
362 }
363 } /* string_matcher_destroy */
365 static char *
366 string_tostring(string_matcher_t *m, char *buf, size_t buflen)
367 {
368 snprintf(buf, buflen, "{ %s%s%s, %p }",
369 m->name ? "'" : "", m->name ? m->name : "NULL", m->name ? "'" : "",
370 m->name_re);
371 return buf;
372 } /* string_tostring */
374 /* initializes a name matcher */
375 static int
376 name_matcher_init(sdb_object_t *obj, va_list ap)
377 {
378 name_matcher_t *m = NAME_M(obj);
379 M(obj)->type = MATCHER_NAME;
380 return string_matcher_init(&m->name, ap);
381 } /* name_matcher_init */
383 static void
384 name_matcher_destroy(sdb_object_t *obj)
385 {
386 name_matcher_t *m = NAME_M(obj);
387 string_matcher_destroy(&m->name);
388 } /* name_matcher_destroy */
390 static char *
391 name_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
392 {
393 char name[buflen + 1];
394 assert(m->type == MATCHER_NAME);
395 snprintf(buf, buflen, "OBJ[%s]{ NAME%s }",
396 SDB_STORE_TYPE_TO_NAME(NAME_M(m)->obj_type),
397 string_tostring(&NAME_M(m)->name, name, sizeof(name)));
398 return buf;
399 } /* name_tostring */
401 static int
402 attr_matcher_init(sdb_object_t *obj, va_list ap)
403 {
404 attr_matcher_t *attr = ATTR_M(obj);
405 const char *name = va_arg(ap, const char *);
407 M(obj)->type = MATCHER_ATTR;
408 if (name) {
409 attr->name = strdup(name);
410 if (! attr->name)
411 return -1;
412 }
413 return string_matcher_init(&attr->value, ap);
414 } /* attr_matcher_init */
416 static void
417 attr_matcher_destroy(sdb_object_t *obj)
418 {
419 attr_matcher_t *attr = ATTR_M(obj);
420 if (attr->name)
421 free(attr->name);
422 attr->name = NULL;
423 string_matcher_destroy(&attr->value);
424 } /* attr_matcher_destroy */
426 static char *
427 attr_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
428 {
429 char value[buflen + 1];
431 if (! m) {
432 snprintf(buf, buflen, "ATTR{}");
433 return buf;
434 }
436 assert(m->type == MATCHER_ATTR);
437 snprintf(buf, buflen, "ATTR[%s]{ VALUE%s }", ATTR_M(m)->name,
438 string_tostring(&ATTR_M(m)->value, value, sizeof(value)));
439 return buf;
440 } /* attr_tostring */
442 static int
443 cond_matcher_init(sdb_object_t *obj, va_list ap)
444 {
445 int type = va_arg(ap, int);
446 sdb_store_cond_t *cond = va_arg(ap, sdb_store_cond_t *);
448 if (! cond)
449 return -1;
451 sdb_object_ref(SDB_OBJ(cond));
453 M(obj)->type = type;
454 COND_M(obj)->cond = cond;
455 return 0;
456 } /* cond_matcher_init */
458 static void
459 cond_matcher_destroy(sdb_object_t *obj)
460 {
461 sdb_object_deref(SDB_OBJ(COND_M(obj)->cond));
462 } /* cond_matcher_destroy */
464 static char *
465 cond_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
466 {
467 if (COND_M(m)->cond->cmp == attr_cmp) {
468 sdb_data_t value = SDB_DATA_INIT;
469 char value_str[buflen];
470 if (sdb_store_expr_eval(ATTR_C(COND_M(m)->cond)->expr, &value))
471 snprintf(value_str, sizeof(value_str), "ERR");
472 else if (sdb_data_format(&value, value_str, sizeof(value_str),
473 SDB_SINGLE_QUOTED) < 0)
474 snprintf(value_str, sizeof(value_str), "ERR");
475 snprintf(buf, buflen, "ATTR[%s]{ %s %s }",
476 ATTR_C(COND_M(m)->cond)->name, MATCHER_SYM(m->type),
477 value_str);
478 sdb_data_free_datum(&value);
479 }
480 return buf;
481 } /* cond_tostring */
483 static int
484 op_matcher_init(sdb_object_t *obj, va_list ap)
485 {
486 M(obj)->type = va_arg(ap, int);
487 if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
488 return -1;
490 OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
491 sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
492 OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
493 sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
495 if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
496 return -1;
497 return 0;
498 } /* op_matcher_init */
500 static void
501 op_matcher_destroy(sdb_object_t *obj)
502 {
503 if (OP_M(obj)->left)
504 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
505 if (OP_M(obj)->right)
506 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
507 } /* op_matcher_destroy */
509 static char *
510 op_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
511 {
512 char left[buflen + 1], right[buflen + 1];
514 if (! m) {
515 /* this should not happen */
516 snprintf(buf, buflen, "()");
517 return buf;
518 }
520 assert((m->type == MATCHER_OR) || (m->type == MATCHER_AND));
521 snprintf(buf, buflen, "(%s, %s, %s)",
522 m->type == MATCHER_OR ? "OR" : "AND",
523 sdb_store_matcher_tostring(OP_M(m)->left, left, sizeof(left)),
524 sdb_store_matcher_tostring(OP_M(m)->right, right, sizeof(right)));
525 return buf;
526 } /* op_tostring */
528 static int
529 uop_matcher_init(sdb_object_t *obj, va_list ap)
530 {
531 M(obj)->type = va_arg(ap, int);
532 if (M(obj)->type != MATCHER_NOT)
533 return -1;
535 UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
536 sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
538 if (! UOP_M(obj)->op)
539 return -1;
540 return 0;
541 } /* uop_matcher_init */
543 static void
544 uop_matcher_destroy(sdb_object_t *obj)
545 {
546 if (UOP_M(obj)->op)
547 sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
548 } /* uop_matcher_destroy */
550 static char *
551 uop_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
552 {
553 char op[buflen + 1];
555 if (! m) {
556 /* this should not happen */
557 snprintf(buf, buflen, "()");
558 return buf;
559 }
561 assert(m->type == MATCHER_NOT);
562 snprintf(buf, buflen, "(NOT, %s)",
563 sdb_store_matcher_tostring(UOP_M(m)->op, op, sizeof(op)));
564 return buf;
565 } /* uop_tostring */
567 static int
568 isnull_matcher_init(sdb_object_t *obj, va_list ap)
569 {
570 const char *name;
572 M(obj)->type = va_arg(ap, int);
573 if (M(obj)->type != MATCHER_ISNULL)
574 return -1;
576 name = va_arg(ap, const char *);
577 if (! name)
578 return -1;
579 ISNULL_M(obj)->attr_name = strdup(name);
580 if (! ISNULL_M(obj)->attr_name)
581 return -1;
582 return 0;
583 } /* isnull_matcher_init */
585 static void
586 isnull_matcher_destroy(sdb_object_t *obj)
587 {
588 if (ISNULL_M(obj)->attr_name)
589 free(ISNULL_M(obj)->attr_name);
590 ISNULL_M(obj)->attr_name = NULL;
591 } /* isnull_matcher_destroy */
593 static char *
594 isnull_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
595 {
596 snprintf(buf, buflen, "(IS NULL, ATTR[%s])", ISNULL_M(m)->attr_name);
597 return buf;
598 } /* isnull_tostring */
600 static sdb_type_t name_type = {
601 /* size = */ sizeof(name_matcher_t),
602 /* init = */ name_matcher_init,
603 /* destroy = */ name_matcher_destroy,
604 };
606 static sdb_type_t attr_type = {
607 /* size = */ sizeof(attr_matcher_t),
608 /* init = */ attr_matcher_init,
609 /* destroy = */ attr_matcher_destroy,
610 };
612 static sdb_type_t cond_type = {
613 /* size = */ sizeof(cond_matcher_t),
614 /* init = */ cond_matcher_init,
615 /* destroy = */ cond_matcher_destroy,
616 };
618 static sdb_type_t op_type = {
619 /* size = */ sizeof(op_matcher_t),
620 /* init = */ op_matcher_init,
621 /* destroy = */ op_matcher_destroy,
622 };
624 static sdb_type_t uop_type = {
625 /* size = */ sizeof(uop_matcher_t),
626 /* init = */ uop_matcher_init,
627 /* destroy = */ uop_matcher_destroy,
628 };
630 static sdb_type_t isnull_type = {
631 /* size = */ sizeof(isnull_matcher_t),
632 /* init = */ isnull_matcher_init,
633 /* destroy = */ isnull_matcher_destroy,
634 };
636 typedef char *(*matcher_tostring_cb)(sdb_store_matcher_t *, char *, size_t);
638 /* this array needs to be indexable by the matcher types;
639 * -> update the enum in store-private.h when updating this */
640 static matcher_tostring_cb
641 matchers_tostring[] = {
642 op_tostring,
643 op_tostring,
644 uop_tostring,
645 name_tostring,
646 attr_tostring,
647 cond_tostring,
648 cond_tostring,
649 cond_tostring,
650 cond_tostring,
651 cond_tostring,
652 isnull_tostring,
653 };
655 /*
656 * public API
657 */
659 sdb_store_cond_t *
660 sdb_store_attr_cond(const char *name, sdb_store_expr_t *expr)
661 {
662 return SDB_STORE_COND(sdb_object_create("attr-cond", attr_cond_type,
663 name, expr));
664 } /* sdb_store_attr_cond */
666 sdb_store_matcher_t *
667 sdb_store_name_matcher(int type, const char *name, _Bool re)
668 {
669 sdb_store_matcher_t *m;
671 if (re)
672 m = M(sdb_object_create("name-matcher", name_type, NULL, name));
673 else
674 m = M(sdb_object_create("name-matcher", name_type, name, NULL));
676 if (! m)
677 return NULL;
679 NAME_M(m)->obj_type = type;
680 return m;
681 } /* sdb_store_name_matcher */
683 sdb_store_matcher_t *
684 sdb_store_attr_matcher(const char *name, const char *value, _Bool re)
685 {
686 sdb_store_matcher_t *m;
688 if (! name)
689 return NULL;
691 if (re)
692 m = M(sdb_object_create("attr-matcher", attr_type,
693 name, NULL, value));
694 else
695 m = M(sdb_object_create("attr-matcher", attr_type,
696 name, value, NULL));
697 return m;
698 } /* sdb_store_attr_matcher */
700 sdb_store_matcher_t *
701 sdb_store_lt_matcher(sdb_store_cond_t *cond)
702 {
703 return M(sdb_object_create("lt-matcher", cond_type,
704 MATCHER_LT, cond));
705 } /* sdb_store_lt_matcher */
707 sdb_store_matcher_t *
708 sdb_store_le_matcher(sdb_store_cond_t *cond)
709 {
710 return M(sdb_object_create("le-matcher", cond_type,
711 MATCHER_LE, cond));
712 } /* sdb_store_le_matcher */
714 sdb_store_matcher_t *
715 sdb_store_eq_matcher(sdb_store_cond_t *cond)
716 {
717 return M(sdb_object_create("eq-matcher", cond_type,
718 MATCHER_EQ, cond));
719 } /* sdb_store_eq_matcher */
721 sdb_store_matcher_t *
722 sdb_store_ge_matcher(sdb_store_cond_t *cond)
723 {
724 return M(sdb_object_create("ge-matcher", cond_type,
725 MATCHER_GE, cond));
726 } /* sdb_store_ge_matcher */
728 sdb_store_matcher_t *
729 sdb_store_gt_matcher(sdb_store_cond_t *cond)
730 {
731 return M(sdb_object_create("gt-matcher", cond_type,
732 MATCHER_GT, cond));
733 } /* sdb_store_gt_matcher */
735 sdb_store_matcher_t *
736 sdb_store_isnull_matcher(const char *attr_name)
737 {
738 return M(sdb_object_create("isnull-matcher", isnull_type,
739 MATCHER_ISNULL, attr_name));
740 } /* sdb_store_isnull_matcher */
742 static sdb_store_matcher_t *
743 parse_attr_cmp(const char *attr, const char *op, sdb_store_expr_t *expr)
744 {
745 sdb_store_matcher_t *(*matcher)(sdb_store_cond_t *) = NULL;
746 sdb_store_matcher_t *m;
747 sdb_store_cond_t *cond;
748 _Bool inv = 0;
750 if (! attr)
751 return NULL;
753 if (! strcasecmp(op, "IS")) {
754 if (! expr)
755 return sdb_store_isnull_matcher(attr);
756 else
757 return NULL;
758 }
759 else if (! expr)
760 return NULL;
761 else if (! strcasecmp(op, "<"))
762 matcher = sdb_store_lt_matcher;
763 else if (! strcasecmp(op, "<="))
764 matcher = sdb_store_le_matcher;
765 else if (! strcasecmp(op, "="))
766 matcher = sdb_store_eq_matcher;
767 else if (! strcasecmp(op, ">="))
768 matcher = sdb_store_ge_matcher;
769 else if (! strcasecmp(op, ">"))
770 matcher = sdb_store_gt_matcher;
771 else if (! strcasecmp(op, "!=")) {
772 matcher = sdb_store_eq_matcher;
773 inv = 1;
774 }
775 else
776 return NULL;
778 cond = sdb_store_attr_cond(attr, expr);
779 if (! cond)
780 return NULL;
782 m = matcher(cond);
783 /* pass ownership to 'm' or destroy in case of an error */
784 sdb_object_deref(SDB_OBJ(cond));
785 if (! m)
786 return NULL;
788 if (inv) {
789 sdb_store_matcher_t *tmp;
790 tmp = sdb_store_inv_matcher(m);
791 /* pass ownership to the inverse matcher */
792 sdb_object_deref(SDB_OBJ(m));
793 m = tmp;
794 }
795 return m;
796 } /* parse_attr_cmp */
798 sdb_store_matcher_t *
799 sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr,
800 const char *op, sdb_store_expr_t *expr)
801 {
802 int type = -1;
803 _Bool inv = 0;
804 _Bool re = 0;
806 sdb_data_t value = SDB_DATA_INIT;
807 sdb_store_matcher_t *m = NULL;
809 if (! strcasecmp(obj_type, "host"))
810 type = SDB_HOST;
811 else if (! strcasecmp(obj_type, "service"))
812 type = SDB_SERVICE;
813 else if (! strcasecmp(obj_type, "attribute"))
814 type = SDB_ATTRIBUTE;
815 else
816 return NULL;
818 /* XXX: this code sucks! */
819 if (! strcasecmp(op, "=")) {
820 /* nothing to do */
821 }
822 else if (! strcasecmp(op, "!=")) {
823 inv = 1;
824 }
825 else if (! strcasecmp(op, "=~")) {
826 re = 1;
827 }
828 else if (! strcasecmp(op, "!~")) {
829 inv = 1;
830 re = 1;
831 }
832 else if (type == SDB_ATTRIBUTE)
833 return parse_attr_cmp(attr, op, expr);
834 else
835 return NULL;
837 if (! expr)
838 return NULL;
840 if (sdb_store_expr_eval(expr, &value))
841 return NULL;
842 if (value.type != SDB_TYPE_STRING) {
843 sdb_data_free_datum(&value);
844 return parse_attr_cmp(attr, op, expr);
845 }
847 if (! attr)
848 m = sdb_store_name_matcher(type, value.data.string, re);
849 else if (type == SDB_ATTRIBUTE)
850 m = sdb_store_attr_matcher(attr, value.data.string, re);
852 sdb_data_free_datum(&value);
854 if (! m)
855 return NULL;
857 if (inv) {
858 sdb_store_matcher_t *tmp;
859 tmp = sdb_store_inv_matcher(m);
860 /* pass ownership to the inverse matcher */
861 sdb_object_deref(SDB_OBJ(m));
862 m = tmp;
863 }
864 return m;
865 } /* sdb_store_matcher_parse_cmp */
867 sdb_store_matcher_t *
868 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
869 {
870 return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
871 left, right));
872 } /* sdb_store_dis_matcher */
874 sdb_store_matcher_t *
875 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
876 {
877 return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
878 left, right));
879 } /* sdb_store_con_matcher */
881 sdb_store_matcher_t *
882 sdb_store_inv_matcher(sdb_store_matcher_t *m)
883 {
884 return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
885 } /* sdb_store_inv_matcher */
887 int
888 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj)
889 {
890 if (obj->type != SDB_HOST)
891 return 0;
893 /* "NULL" always matches */
894 if ((! m) || (! obj))
895 return 1;
897 if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
898 return 0;
900 return matchers[m->type](m, HOST(obj));
901 } /* sdb_store_matcher_matches */
903 char *
904 sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
905 {
906 if (! m)
907 return NULL;
909 if ((m->type < 0)
910 || (((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers_tostring))))
911 return NULL;
912 return matchers_tostring[m->type](m, buf, buflen);
913 } /* sdb_store_matcher_tostring */
915 int
916 sdb_store_scan(sdb_store_matcher_t *m, sdb_store_lookup_cb cb,
917 void *user_data)
918 {
919 scan_iter_data_t data = { m, cb, user_data };
921 if (! cb)
922 return -1;
923 return sdb_store_iterate(scan_iter, &data);
924 } /* sdb_store_scan */
926 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */