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_matcher_t *filter;
59 sdb_store_lookup_cb cb;
60 void *user_data;
61 } scan_iter_data_t;
63 /*
64 * private helper functions
65 */
67 static int
68 scan_iter(sdb_store_obj_t *obj, void *user_data)
69 {
70 scan_iter_data_t *d = user_data;
72 if (sdb_store_matcher_matches(d->m, obj, d->filter))
73 return d->cb(obj, d->user_data);
74 return 0;
75 } /* scan_iter */
77 static sdb_attribute_t *
78 attr_get(sdb_host_t *host, const char *name, sdb_store_matcher_t *filter)
79 {
80 sdb_avltree_iter_t *iter = NULL;
81 sdb_attribute_t *attr = NULL;
83 iter = sdb_avltree_get_iter(host->attributes);
84 while (sdb_avltree_iter_has_next(iter)) {
85 sdb_attribute_t *a = ATTR(sdb_avltree_iter_get_next(iter));
87 if (strcasecmp(name, SDB_OBJ(a)->name))
88 continue;
90 assert(STORE_OBJ(a)->type == SDB_ATTRIBUTE);
91 attr = a;
92 break;
93 }
94 sdb_avltree_iter_destroy(iter);
96 if (filter && (! sdb_store_matcher_matches(filter, STORE_OBJ(attr),
97 NULL)))
98 return NULL;
99 return attr;
100 } /* attr_get */
102 /*
103 * conditional implementations
104 */
106 static int
107 attr_cmp(sdb_store_obj_t *obj, sdb_store_cond_t *cond,
108 sdb_store_matcher_t *filter)
109 {
110 sdb_attribute_t *attr;
111 sdb_data_t value = SDB_DATA_INIT;
112 int status;
114 if (obj->type != SDB_HOST)
115 return INT_MAX;
117 if (sdb_store_expr_eval(ATTR_C(cond)->expr, &value))
118 return INT_MAX;
120 attr = attr_get(HOST(obj), ATTR_C(cond)->name, filter);
121 if (! attr)
122 status = INT_MAX;
123 else if (attr->value.type != value.type)
124 status = INT_MAX;
125 else
126 status = sdb_data_cmp(&attr->value, &value);
127 sdb_data_free_datum(&value);
128 return status;
129 } /* attr_cmp */
131 static int
132 obj_cmp(sdb_store_obj_t *obj, sdb_store_cond_t *cond,
133 sdb_store_matcher_t __attribute__((unused)) *filter)
134 {
135 sdb_data_t obj_value = SDB_DATA_INIT;
136 sdb_data_t value = SDB_DATA_INIT;
137 int status;
139 switch (OBJ_C(cond)->field) {
140 case SDB_FIELD_LAST_UPDATE:
141 obj_value.type = SDB_TYPE_DATETIME;
142 obj_value.data.datetime = obj->last_update;
143 break;
144 case SDB_FIELD_AGE:
145 obj_value.type = SDB_TYPE_DATETIME;
146 obj_value.data.datetime = sdb_gettime() - obj->last_update;
147 break;
148 case SDB_FIELD_INTERVAL:
149 obj_value.type = SDB_TYPE_DATETIME;
150 obj_value.data.datetime = obj->interval;
151 break;
152 case SDB_FIELD_BACKEND:
153 obj_value.type = SDB_TYPE_STRING;
154 obj_value.data.string = NULL; /* handled separately */
155 break;
156 default:
157 return INT_MAX;
158 }
160 if (sdb_store_expr_eval(OBJ_C(cond)->expr, &value))
161 return INT_MAX;
163 if (obj_value.type != value.type) {
164 sdb_data_free_datum(&value);
165 return INT_MAX;
166 }
167 else if (OBJ_C(cond)->field == SDB_FIELD_BACKEND) {
168 /* this implementation is not actually a conditional but rather checks
169 * for equality (or rather, existence) only */
170 size_t i;
171 status = INT_MAX;
172 for (i = 0; i < obj->backends_num; ++i) {
173 if (! strcasecmp(obj->backends[i], value.data.string)) {
174 status = 0;
175 break;
176 }
177 }
178 }
179 else {
180 status = sdb_data_cmp(&obj_value, &value);
181 }
182 sdb_data_free_datum(&value);
183 return status;
184 } /* obj_cmp */
186 /*
187 * matcher implementations
188 */
190 static int
191 match_string(string_matcher_t *m, const char *name)
192 {
193 if ((! m->name) && (! m->name_re))
194 return 1;
196 if (! name)
197 name = "";
199 if (m->name && strcasecmp(m->name, name))
200 return 0;
201 if (m->name_re && regexec(m->name_re, name,
202 /* matches */ 0, NULL, /* flags = */ 0))
203 return 0;
204 return 1;
205 } /* match_string */
207 static int
208 match_logical(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
209 sdb_store_matcher_t *filter)
210 {
211 int status;
213 assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
214 assert(OP_M(m)->left && OP_M(m)->right);
216 status = sdb_store_matcher_matches(OP_M(m)->left, obj, filter);
218 /* lazy evaluation */
219 if ((! status) && (m->type == MATCHER_AND))
220 return status;
221 else if (status && (m->type == MATCHER_OR))
222 return status;
224 return sdb_store_matcher_matches(OP_M(m)->right, obj, filter);
225 } /* match_logical */
227 static int
228 match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
229 sdb_store_matcher_t *filter)
230 {
231 assert(m->type == MATCHER_NOT);
232 assert(UOP_M(m)->op);
234 return !sdb_store_matcher_matches(UOP_M(m)->op, obj, filter);
235 } /* match_unary */
237 static int
238 match_name(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
239 sdb_store_matcher_t *filter)
240 {
241 sdb_avltree_iter_t *iter = NULL;
242 int status = 0;
244 assert(m->type == MATCHER_NAME);
246 if (obj->type == NAME_M(m)->obj_type)
247 return match_string(&NAME_M(m)->name, SDB_OBJ(obj)->name);
248 else if (obj->type != SDB_HOST)
249 return 0;
251 switch (NAME_M(m)->obj_type) {
252 case SDB_SERVICE:
253 iter = sdb_avltree_get_iter(HOST(obj)->services);
254 break;
255 case SDB_ATTRIBUTE:
256 iter = sdb_avltree_get_iter(HOST(obj)->attributes);
257 break;
258 }
260 while (sdb_avltree_iter_has_next(iter)) {
261 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
262 if (filter && (! sdb_store_matcher_matches(filter, STORE_OBJ(child),
263 NULL)))
264 continue;
265 if (match_string(&NAME_M(m)->name, child->name)) {
266 status = 1;
267 break;
268 }
269 }
270 sdb_avltree_iter_destroy(iter);
271 return status;
272 } /* match_name */
274 static int
275 match_attr(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
276 sdb_store_matcher_t *filter)
277 {
278 sdb_attribute_t *attr;
280 assert(m->type == MATCHER_ATTR);
281 assert(ATTR_M(m)->name);
283 if (obj->type != SDB_HOST)
284 return 0;
286 attr = attr_get(HOST(obj), ATTR_M(m)->name, filter);
287 if (attr) {
288 char buf[sdb_data_strlen(&attr->value) + 1];
289 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
290 return 0;
291 if (match_string(&ATTR_M(m)->value, buf))
292 return 1;
293 }
294 return 0;
295 } /* match_attr */
297 static int
298 match_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
299 sdb_store_matcher_t *filter)
300 {
301 int status;
302 assert(m->type == MATCHER_LT);
303 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
304 return (status != INT_MAX) && (status < 0);
305 } /* match_lt */
307 static int
308 match_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
309 sdb_store_matcher_t *filter)
310 {
311 int status;
312 assert(m->type == MATCHER_LE);
313 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
314 return (status != INT_MAX) && (status <= 0);
315 } /* match_le */
317 static int
318 match_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
319 sdb_store_matcher_t *filter)
320 {
321 int status;
322 assert(m->type == MATCHER_EQ);
323 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
324 return (status != INT_MAX) && (! status);
325 } /* match_eq */
327 static int
328 match_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
329 sdb_store_matcher_t *filter)
330 {
331 int status;
332 assert(m->type == MATCHER_GE);
333 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
334 return (status != INT_MAX) && (status >= 0);
335 } /* match_ge */
337 static int
338 match_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
339 sdb_store_matcher_t *filter)
340 {
341 int status;
342 assert(m->type == MATCHER_GT);
343 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
344 return (status != INT_MAX) && (status > 0);
345 } /* match_gt */
347 static int
348 match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
349 sdb_store_matcher_t *filter)
350 {
351 assert(m->type == MATCHER_ISNULL);
352 if (obj->type != SDB_HOST)
353 return 0;
354 return attr_get(HOST(obj), ISNULL_M(m)->attr_name, filter) == NULL;
355 } /* match_isnull */
357 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_obj_t *,
358 sdb_store_matcher_t *);
360 /* this array needs to be indexable by the matcher types;
361 * -> update the enum in store-private.h when updating this */
362 static matcher_cb
363 matchers[] = {
364 match_logical,
365 match_logical,
366 match_unary,
367 match_name,
368 match_attr,
369 match_lt,
370 match_le,
371 match_eq,
372 match_ge,
373 match_gt,
374 match_isnull,
375 };
377 /*
378 * private conditional types
379 */
381 static int
382 attr_cond_init(sdb_object_t *obj, va_list ap)
383 {
384 const char *name = va_arg(ap, const char *);
385 sdb_store_expr_t *expr = va_arg(ap, sdb_store_expr_t *);
387 if (! name)
388 return -1;
390 SDB_STORE_COND(obj)->cmp = attr_cmp;
392 ATTR_C(obj)->name = strdup(name);
393 if (! ATTR_C(obj)->name)
394 return -1;
395 ATTR_C(obj)->expr = expr;
396 sdb_object_ref(SDB_OBJ(expr));
397 return 0;
398 } /* attr_cond_init */
400 static void
401 attr_cond_destroy(sdb_object_t *obj)
402 {
403 if (ATTR_C(obj)->name)
404 free(ATTR_C(obj)->name);
405 sdb_object_deref(SDB_OBJ(ATTR_C(obj)->expr));
406 } /* attr_cond_destroy */
408 static sdb_type_t attr_cond_type = {
409 /* size = */ sizeof(attr_cond_t),
410 /* init = */ attr_cond_init,
411 /* destroy = */ attr_cond_destroy,
412 };
414 static int
415 obj_cond_init(sdb_object_t *obj, va_list ap)
416 {
417 int field = va_arg(ap, int);
418 sdb_store_expr_t *expr = va_arg(ap, sdb_store_expr_t *);
420 SDB_STORE_COND(obj)->cmp = obj_cmp;
422 OBJ_C(obj)->field = field;
423 OBJ_C(obj)->expr = expr;
424 sdb_object_ref(SDB_OBJ(expr));
425 return 0;
426 } /* obj_cond_init */
428 static void
429 obj_cond_destroy(sdb_object_t *obj)
430 {
431 sdb_object_deref(SDB_OBJ(OBJ_C(obj)->expr));
432 } /* obj_cond_destroy */
434 static sdb_type_t obj_cond_type = {
435 /* size = */ sizeof(obj_cond_t),
436 /* init = */ obj_cond_init,
437 /* destroy = */ obj_cond_destroy,
438 };
440 /*
441 * private matcher types
442 */
444 /* initializes a string matcher consuming two elements from ap */
445 static int
446 string_matcher_init(string_matcher_t *m, va_list ap)
447 {
448 const char *name = va_arg(ap, const char *);
449 const char *name_re = va_arg(ap, const char *);
451 if (name) {
452 m->name = strdup(name);
453 if (! m->name)
454 return -1;
455 }
456 if (name_re) {
457 m->name_re = malloc(sizeof(*m->name_re));
458 if (! m->name_re)
459 return -1;
460 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
461 return -1;
462 }
463 return 0;
464 } /* string_matcher_init */
466 static void
467 string_matcher_destroy(string_matcher_t *m)
468 {
469 if (m->name)
470 free(m->name);
471 if (m->name_re) {
472 regfree(m->name_re);
473 free(m->name_re);
474 }
475 } /* string_matcher_destroy */
477 static char *
478 string_tostring(string_matcher_t *m, char *buf, size_t buflen)
479 {
480 snprintf(buf, buflen, "{ %s%s%s, %p }",
481 m->name ? "'" : "", m->name ? m->name : "NULL", m->name ? "'" : "",
482 m->name_re);
483 return buf;
484 } /* string_tostring */
486 /* initializes a name matcher */
487 static int
488 name_matcher_init(sdb_object_t *obj, va_list ap)
489 {
490 name_matcher_t *m = NAME_M(obj);
491 M(obj)->type = MATCHER_NAME;
492 return string_matcher_init(&m->name, ap);
493 } /* name_matcher_init */
495 static void
496 name_matcher_destroy(sdb_object_t *obj)
497 {
498 name_matcher_t *m = NAME_M(obj);
499 string_matcher_destroy(&m->name);
500 } /* name_matcher_destroy */
502 static char *
503 name_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
504 {
505 char name[buflen + 1];
506 assert(m->type == MATCHER_NAME);
507 snprintf(buf, buflen, "OBJ[%s]{ NAME%s }",
508 SDB_STORE_TYPE_TO_NAME(NAME_M(m)->obj_type),
509 string_tostring(&NAME_M(m)->name, name, sizeof(name)));
510 return buf;
511 } /* name_tostring */
513 static int
514 attr_matcher_init(sdb_object_t *obj, va_list ap)
515 {
516 attr_matcher_t *attr = ATTR_M(obj);
517 const char *name = va_arg(ap, const char *);
519 M(obj)->type = MATCHER_ATTR;
520 if (name) {
521 attr->name = strdup(name);
522 if (! attr->name)
523 return -1;
524 }
525 return string_matcher_init(&attr->value, ap);
526 } /* attr_matcher_init */
528 static void
529 attr_matcher_destroy(sdb_object_t *obj)
530 {
531 attr_matcher_t *attr = ATTR_M(obj);
532 if (attr->name)
533 free(attr->name);
534 attr->name = NULL;
535 string_matcher_destroy(&attr->value);
536 } /* attr_matcher_destroy */
538 static char *
539 attr_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
540 {
541 char value[buflen + 1];
543 if (! m) {
544 snprintf(buf, buflen, "ATTR{}");
545 return buf;
546 }
548 assert(m->type == MATCHER_ATTR);
549 snprintf(buf, buflen, "ATTR[%s]{ VALUE%s }", ATTR_M(m)->name,
550 string_tostring(&ATTR_M(m)->value, value, sizeof(value)));
551 return buf;
552 } /* attr_tostring */
554 static int
555 cond_matcher_init(sdb_object_t *obj, va_list ap)
556 {
557 int type = va_arg(ap, int);
558 sdb_store_cond_t *cond = va_arg(ap, sdb_store_cond_t *);
560 if (! cond)
561 return -1;
563 sdb_object_ref(SDB_OBJ(cond));
565 M(obj)->type = type;
566 COND_M(obj)->cond = cond;
567 return 0;
568 } /* cond_matcher_init */
570 static void
571 cond_matcher_destroy(sdb_object_t *obj)
572 {
573 sdb_object_deref(SDB_OBJ(COND_M(obj)->cond));
574 } /* cond_matcher_destroy */
576 static char *
577 cond_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
578 {
579 const char *type, *id;
580 sdb_data_t value = SDB_DATA_INIT;
581 char value_str[buflen];
582 sdb_store_expr_t *expr;
584 if (COND_M(m)->cond->cmp == attr_cmp) {
585 type = "ATTR";
586 id = ATTR_C(COND_M(m)->cond)->name;
587 expr = ATTR_C(COND_M(m)->cond)->expr;
588 }
589 else if (COND_M(m)->cond->cmp == obj_cmp) {
590 type = "OBJ";
591 id = SDB_FIELD_TO_NAME(OBJ_C(COND_M(m)->cond)->field);
592 expr = OBJ_C(COND_M(m)->cond)->expr;
593 }
594 else {
595 snprintf(buf, buflen, "<unknown>");
596 return buf;
597 }
599 if (sdb_store_expr_eval(expr, &value))
600 snprintf(value_str, sizeof(value_str), "ERR");
601 else if (sdb_data_format(&value, value_str, sizeof(value_str),
602 SDB_SINGLE_QUOTED) < 0)
603 snprintf(value_str, sizeof(value_str), "ERR");
604 snprintf(buf, buflen, "%s[%s]{ %s %s }", type, id,
605 MATCHER_SYM(m->type), value_str);
606 sdb_data_free_datum(&value);
607 return buf;
608 } /* cond_tostring */
610 static int
611 op_matcher_init(sdb_object_t *obj, va_list ap)
612 {
613 M(obj)->type = va_arg(ap, int);
614 if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
615 return -1;
617 OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
618 sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
619 OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
620 sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
622 if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
623 return -1;
624 return 0;
625 } /* op_matcher_init */
627 static void
628 op_matcher_destroy(sdb_object_t *obj)
629 {
630 if (OP_M(obj)->left)
631 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
632 if (OP_M(obj)->right)
633 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
634 } /* op_matcher_destroy */
636 static char *
637 op_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
638 {
639 char left[buflen + 1], right[buflen + 1];
641 if (! m) {
642 /* this should not happen */
643 snprintf(buf, buflen, "()");
644 return buf;
645 }
647 assert((m->type == MATCHER_OR) || (m->type == MATCHER_AND));
648 snprintf(buf, buflen, "(%s, %s, %s)",
649 m->type == MATCHER_OR ? "OR" : "AND",
650 sdb_store_matcher_tostring(OP_M(m)->left, left, sizeof(left)),
651 sdb_store_matcher_tostring(OP_M(m)->right, right, sizeof(right)));
652 return buf;
653 } /* op_tostring */
655 static int
656 uop_matcher_init(sdb_object_t *obj, va_list ap)
657 {
658 M(obj)->type = va_arg(ap, int);
659 if (M(obj)->type != MATCHER_NOT)
660 return -1;
662 UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
663 sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
665 if (! UOP_M(obj)->op)
666 return -1;
667 return 0;
668 } /* uop_matcher_init */
670 static void
671 uop_matcher_destroy(sdb_object_t *obj)
672 {
673 if (UOP_M(obj)->op)
674 sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
675 } /* uop_matcher_destroy */
677 static char *
678 uop_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
679 {
680 char op[buflen + 1];
682 if (! m) {
683 /* this should not happen */
684 snprintf(buf, buflen, "()");
685 return buf;
686 }
688 assert(m->type == MATCHER_NOT);
689 snprintf(buf, buflen, "(NOT, %s)",
690 sdb_store_matcher_tostring(UOP_M(m)->op, op, sizeof(op)));
691 return buf;
692 } /* uop_tostring */
694 static int
695 isnull_matcher_init(sdb_object_t *obj, va_list ap)
696 {
697 const char *name;
699 M(obj)->type = va_arg(ap, int);
700 if (M(obj)->type != MATCHER_ISNULL)
701 return -1;
703 name = va_arg(ap, const char *);
704 if (! name)
705 return -1;
706 ISNULL_M(obj)->attr_name = strdup(name);
707 if (! ISNULL_M(obj)->attr_name)
708 return -1;
709 return 0;
710 } /* isnull_matcher_init */
712 static void
713 isnull_matcher_destroy(sdb_object_t *obj)
714 {
715 if (ISNULL_M(obj)->attr_name)
716 free(ISNULL_M(obj)->attr_name);
717 ISNULL_M(obj)->attr_name = NULL;
718 } /* isnull_matcher_destroy */
720 static char *
721 isnull_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
722 {
723 snprintf(buf, buflen, "(IS NULL, ATTR[%s])", ISNULL_M(m)->attr_name);
724 return buf;
725 } /* isnull_tostring */
727 static sdb_type_t name_type = {
728 /* size = */ sizeof(name_matcher_t),
729 /* init = */ name_matcher_init,
730 /* destroy = */ name_matcher_destroy,
731 };
733 static sdb_type_t attr_type = {
734 /* size = */ sizeof(attr_matcher_t),
735 /* init = */ attr_matcher_init,
736 /* destroy = */ attr_matcher_destroy,
737 };
739 static sdb_type_t cond_type = {
740 /* size = */ sizeof(cond_matcher_t),
741 /* init = */ cond_matcher_init,
742 /* destroy = */ cond_matcher_destroy,
743 };
745 static sdb_type_t op_type = {
746 /* size = */ sizeof(op_matcher_t),
747 /* init = */ op_matcher_init,
748 /* destroy = */ op_matcher_destroy,
749 };
751 static sdb_type_t uop_type = {
752 /* size = */ sizeof(uop_matcher_t),
753 /* init = */ uop_matcher_init,
754 /* destroy = */ uop_matcher_destroy,
755 };
757 static sdb_type_t isnull_type = {
758 /* size = */ sizeof(isnull_matcher_t),
759 /* init = */ isnull_matcher_init,
760 /* destroy = */ isnull_matcher_destroy,
761 };
763 typedef char *(*matcher_tostring_cb)(sdb_store_matcher_t *, char *, size_t);
765 /* this array needs to be indexable by the matcher types;
766 * -> update the enum in store-private.h when updating this */
767 static matcher_tostring_cb
768 matchers_tostring[] = {
769 op_tostring,
770 op_tostring,
771 uop_tostring,
772 name_tostring,
773 attr_tostring,
774 cond_tostring,
775 cond_tostring,
776 cond_tostring,
777 cond_tostring,
778 cond_tostring,
779 isnull_tostring,
780 };
782 /*
783 * public API
784 */
786 sdb_store_cond_t *
787 sdb_store_attr_cond(const char *name, sdb_store_expr_t *expr)
788 {
789 return SDB_STORE_COND(sdb_object_create("attr-cond", attr_cond_type,
790 name, expr));
791 } /* sdb_store_attr_cond */
793 sdb_store_cond_t *
794 sdb_store_obj_cond(int field, sdb_store_expr_t *expr)
795 {
796 return SDB_STORE_COND(sdb_object_create("obj-cond", obj_cond_type,
797 field, expr));
798 } /* sdb_store_obj_cond */
800 sdb_store_matcher_t *
801 sdb_store_name_matcher(int type, const char *name, _Bool re)
802 {
803 sdb_store_matcher_t *m;
805 if (re)
806 m = M(sdb_object_create("name-matcher", name_type, NULL, name));
807 else
808 m = M(sdb_object_create("name-matcher", name_type, name, NULL));
810 if (! m)
811 return NULL;
813 NAME_M(m)->obj_type = type;
814 return m;
815 } /* sdb_store_name_matcher */
817 sdb_store_matcher_t *
818 sdb_store_attr_matcher(const char *name, const char *value, _Bool re)
819 {
820 sdb_store_matcher_t *m;
822 if (! name)
823 return NULL;
825 if (re)
826 m = M(sdb_object_create("attr-matcher", attr_type,
827 name, NULL, value));
828 else
829 m = M(sdb_object_create("attr-matcher", attr_type,
830 name, value, NULL));
831 return m;
832 } /* sdb_store_attr_matcher */
834 sdb_store_matcher_t *
835 sdb_store_lt_matcher(sdb_store_cond_t *cond)
836 {
837 return M(sdb_object_create("lt-matcher", cond_type,
838 MATCHER_LT, cond));
839 } /* sdb_store_lt_matcher */
841 sdb_store_matcher_t *
842 sdb_store_le_matcher(sdb_store_cond_t *cond)
843 {
844 return M(sdb_object_create("le-matcher", cond_type,
845 MATCHER_LE, cond));
846 } /* sdb_store_le_matcher */
848 sdb_store_matcher_t *
849 sdb_store_eq_matcher(sdb_store_cond_t *cond)
850 {
851 return M(sdb_object_create("eq-matcher", cond_type,
852 MATCHER_EQ, cond));
853 } /* sdb_store_eq_matcher */
855 sdb_store_matcher_t *
856 sdb_store_ge_matcher(sdb_store_cond_t *cond)
857 {
858 return M(sdb_object_create("ge-matcher", cond_type,
859 MATCHER_GE, cond));
860 } /* sdb_store_ge_matcher */
862 sdb_store_matcher_t *
863 sdb_store_gt_matcher(sdb_store_cond_t *cond)
864 {
865 return M(sdb_object_create("gt-matcher", cond_type,
866 MATCHER_GT, cond));
867 } /* sdb_store_gt_matcher */
869 sdb_store_matcher_t *
870 sdb_store_isnull_matcher(const char *attr_name)
871 {
872 return M(sdb_object_create("isnull-matcher", isnull_type,
873 MATCHER_ISNULL, attr_name));
874 } /* sdb_store_isnull_matcher */
876 static sdb_store_matcher_t *
877 parse_attr_cmp(const char *attr, const char *op, sdb_store_expr_t *expr)
878 {
879 sdb_store_matcher_t *(*matcher)(sdb_store_cond_t *) = NULL;
880 sdb_store_matcher_t *m;
881 sdb_store_cond_t *cond;
882 _Bool inv = 0;
884 if (! attr)
885 return NULL;
887 if (! strcasecmp(op, "IS")) {
888 if (! expr)
889 return sdb_store_isnull_matcher(attr);
890 else
891 return NULL;
892 }
893 else if (! expr)
894 return NULL;
895 else if (! strcasecmp(op, "<"))
896 matcher = sdb_store_lt_matcher;
897 else if (! strcasecmp(op, "<="))
898 matcher = sdb_store_le_matcher;
899 else if (! strcasecmp(op, "="))
900 matcher = sdb_store_eq_matcher;
901 else if (! strcasecmp(op, ">="))
902 matcher = sdb_store_ge_matcher;
903 else if (! strcasecmp(op, ">"))
904 matcher = sdb_store_gt_matcher;
905 else if (! strcasecmp(op, "!=")) {
906 matcher = sdb_store_eq_matcher;
907 inv = 1;
908 }
909 else
910 return NULL;
912 cond = sdb_store_attr_cond(attr, expr);
913 if (! cond)
914 return NULL;
916 m = matcher(cond);
917 /* pass ownership to 'm' or destroy in case of an error */
918 sdb_object_deref(SDB_OBJ(cond));
919 if (! m)
920 return NULL;
922 if (inv) {
923 sdb_store_matcher_t *tmp;
924 tmp = sdb_store_inv_matcher(m);
925 /* pass ownership to the inverse matcher */
926 sdb_object_deref(SDB_OBJ(m));
927 m = tmp;
928 }
929 return m;
930 } /* parse_attr_cmp */
932 sdb_store_matcher_t *
933 sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr,
934 const char *op, sdb_store_expr_t *expr)
935 {
936 int type = -1;
937 _Bool inv = 0;
938 _Bool re = 0;
940 sdb_data_t value = SDB_DATA_INIT;
941 sdb_store_matcher_t *m = NULL;
943 if (! strcasecmp(obj_type, "host"))
944 type = SDB_HOST;
945 else if (! strcasecmp(obj_type, "service"))
946 type = SDB_SERVICE;
947 else if (! strcasecmp(obj_type, "attribute"))
948 type = SDB_ATTRIBUTE;
949 else
950 return NULL;
952 /* XXX: this code sucks! */
953 if (! strcasecmp(op, "=")) {
954 /* nothing to do */
955 }
956 else if (! strcasecmp(op, "!=")) {
957 inv = 1;
958 }
959 else if (! strcasecmp(op, "=~")) {
960 re = 1;
961 }
962 else if (! strcasecmp(op, "!~")) {
963 inv = 1;
964 re = 1;
965 }
966 else if (type == SDB_ATTRIBUTE)
967 return parse_attr_cmp(attr, op, expr);
968 else
969 return NULL;
971 if (! expr)
972 return NULL;
974 if (sdb_store_expr_eval(expr, &value))
975 return NULL;
976 if (value.type != SDB_TYPE_STRING) {
977 sdb_data_free_datum(&value);
978 return parse_attr_cmp(attr, op, expr);
979 }
981 if (! attr)
982 m = sdb_store_name_matcher(type, value.data.string, re);
983 else if (type == SDB_ATTRIBUTE)
984 m = sdb_store_attr_matcher(attr, value.data.string, re);
986 sdb_data_free_datum(&value);
988 if (! m)
989 return NULL;
991 if (inv) {
992 sdb_store_matcher_t *tmp;
993 tmp = sdb_store_inv_matcher(m);
994 /* pass ownership to the inverse matcher */
995 sdb_object_deref(SDB_OBJ(m));
996 m = tmp;
997 }
998 return m;
999 } /* sdb_store_matcher_parse_cmp */
1001 sdb_store_matcher_t *
1002 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
1003 {
1004 return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
1005 left, right));
1006 } /* sdb_store_dis_matcher */
1008 sdb_store_matcher_t *
1009 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
1010 {
1011 return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
1012 left, right));
1013 } /* sdb_store_con_matcher */
1015 sdb_store_matcher_t *
1016 sdb_store_inv_matcher(sdb_store_matcher_t *m)
1017 {
1018 return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
1019 } /* sdb_store_inv_matcher */
1021 int
1022 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
1023 sdb_store_matcher_t *filter)
1024 {
1025 if (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))
1026 return 0;
1028 /* "NULL" always matches */
1029 if ((! m) || (! obj))
1030 return 1;
1032 if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
1033 return 0;
1035 return matchers[m->type](m, obj, filter);
1036 } /* sdb_store_matcher_matches */
1038 char *
1039 sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
1040 {
1041 if (! m)
1042 return NULL;
1044 if ((m->type < 0)
1045 || (((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers_tostring))))
1046 return NULL;
1047 return matchers_tostring[m->type](m, buf, buflen);
1048 } /* sdb_store_matcher_tostring */
1050 int
1051 sdb_store_scan(sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
1052 sdb_store_lookup_cb cb, void *user_data)
1053 {
1054 scan_iter_data_t data = { m, filter, cb, user_data };
1056 if (! cb)
1057 return -1;
1058 return sdb_store_iterate(scan_iter, &data);
1059 } /* sdb_store_scan */
1061 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */