5f23cd753d9b4cda959c7111aae2d76fd8c1a34f
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, obj, &value, filter))
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 = sdb_data_strcmp(&attr->value, &value);
125 else
126 status = sdb_data_cmp(&attr->value, &value);
127 sdb_data_free_datum(&value);
128 return status;
129 } /* attr_cmp */
131 /*
132 * matcher implementations
133 */
135 static int
136 match_string(string_matcher_t *m, const char *name)
137 {
138 if ((! m->name) && (! m->name_re))
139 return 1;
141 if (! name)
142 name = "";
144 if (m->name && strcasecmp(m->name, name))
145 return 0;
146 if (m->name_re && regexec(m->name_re, name,
147 /* matches */ 0, NULL, /* flags = */ 0))
148 return 0;
149 return 1;
150 } /* match_string */
152 static int
153 match_logical(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
154 sdb_store_matcher_t *filter)
155 {
156 int status;
158 assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
159 assert(OP_M(m)->left && OP_M(m)->right);
161 status = sdb_store_matcher_matches(OP_M(m)->left, obj, filter);
163 /* lazy evaluation */
164 if ((! status) && (m->type == MATCHER_AND))
165 return status;
166 else if (status && (m->type == MATCHER_OR))
167 return status;
169 return sdb_store_matcher_matches(OP_M(m)->right, obj, filter);
170 } /* match_logical */
172 static int
173 match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
174 sdb_store_matcher_t *filter)
175 {
176 assert(m->type == MATCHER_NOT);
177 assert(UOP_M(m)->op);
179 return !sdb_store_matcher_matches(UOP_M(m)->op, obj, filter);
180 } /* match_unary */
182 static int
183 match_name(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
184 sdb_store_matcher_t *filter)
185 {
186 sdb_avltree_iter_t *iter = NULL;
187 int status = 0;
189 assert(m->type == MATCHER_NAME);
191 if (obj->type == NAME_M(m)->obj_type)
192 return match_string(&NAME_M(m)->name, SDB_OBJ(obj)->name);
193 else if (obj->type != SDB_HOST)
194 return 0;
196 switch (NAME_M(m)->obj_type) {
197 case SDB_SERVICE:
198 iter = sdb_avltree_get_iter(HOST(obj)->services);
199 break;
200 case SDB_METRIC:
201 iter = sdb_avltree_get_iter(HOST(obj)->metrics);
202 break;
203 case SDB_ATTRIBUTE:
204 iter = sdb_avltree_get_iter(HOST(obj)->attributes);
205 break;
206 }
208 while (sdb_avltree_iter_has_next(iter)) {
209 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
210 if (filter && (! sdb_store_matcher_matches(filter, STORE_OBJ(child),
211 NULL)))
212 continue;
213 if (match_string(&NAME_M(m)->name, child->name)) {
214 status = 1;
215 break;
216 }
217 }
218 sdb_avltree_iter_destroy(iter);
219 return status;
220 } /* match_name */
222 static int
223 match_attr(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
224 sdb_store_matcher_t *filter)
225 {
226 sdb_attribute_t *attr;
228 assert(m->type == MATCHER_ATTR);
229 assert(ATTR_M(m)->name);
231 if (obj->type != SDB_HOST)
232 return 0;
234 attr = attr_get(HOST(obj), ATTR_M(m)->name, filter);
235 if (attr) {
236 char buf[sdb_data_strlen(&attr->value) + 1];
237 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
238 return 0;
239 if (match_string(&ATTR_M(m)->value, buf))
240 return 1;
241 }
242 return 0;
243 } /* match_attr */
245 static int
246 match_child(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
247 sdb_store_matcher_t *filter)
248 {
249 sdb_avltree_iter_t *iter = NULL;
250 int status = 0;
252 assert((m->type == MATCHER_SERVICE)
253 || (m->type == MATCHER_METRIC)
254 || (m->type == MATCHER_ATTRIBUTE));
256 /* TODO: support all object types */
257 if (obj->type != SDB_HOST)
258 return 0;
260 if (m->type == MATCHER_SERVICE)
261 iter = sdb_avltree_get_iter(HOST(obj)->services);
262 else if (m->type == MATCHER_METRIC)
263 iter = sdb_avltree_get_iter(HOST(obj)->metrics);
264 else if (m->type == SDB_ATTRIBUTE)
265 iter = sdb_avltree_get_iter(HOST(obj)->attributes);
267 while (sdb_avltree_iter_has_next(iter)) {
268 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
269 if (filter && (! sdb_store_matcher_matches(filter,
270 STORE_OBJ(child), NULL)))
271 continue;
273 if (sdb_store_matcher_matches(CHILD_M(m)->m, obj, filter)) {
274 status = 1;
275 break;
276 }
277 }
278 sdb_avltree_iter_destroy(iter);
279 return status;
280 } /* match_child */
282 static int
283 match_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
284 sdb_store_matcher_t *filter)
285 {
286 int status;
287 assert(m->type == MATCHER_LT);
288 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
289 return (status != INT_MAX) && (status < 0);
290 } /* match_lt */
292 static int
293 match_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
294 sdb_store_matcher_t *filter)
295 {
296 int status;
297 assert(m->type == MATCHER_LE);
298 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
299 return (status != INT_MAX) && (status <= 0);
300 } /* match_le */
302 static int
303 match_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
304 sdb_store_matcher_t *filter)
305 {
306 int status;
307 assert(m->type == MATCHER_EQ);
308 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
309 return (status != INT_MAX) && (! status);
310 } /* match_eq */
312 static int
313 match_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
314 sdb_store_matcher_t *filter)
315 {
316 int status;
317 assert(m->type == MATCHER_GE);
318 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
319 return (status != INT_MAX) && (status >= 0);
320 } /* match_ge */
322 static int
323 match_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
324 sdb_store_matcher_t *filter)
325 {
326 int status;
327 assert(m->type == MATCHER_GT);
328 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond, filter);
329 return (status != INT_MAX) && (status > 0);
330 } /* match_gt */
332 /*
333 * cmp_expr:
334 * Compare the values of two expressions when evaluating them using the
335 * specified stored object and filter. Returns a value less than, equal to, or
336 * greater than zero if the value of the first expression compares less than,
337 * equal to, or greater than the value of the second expression. Returns
338 * INT_MAX if any of the expressions could not be evaluated or if any of them
339 * evaluated to NULL.
340 */
341 static int
342 cmp_expr(sdb_store_expr_t *e1, sdb_store_expr_t *e2,
343 sdb_store_obj_t *obj, sdb_store_matcher_t *filter)
344 {
345 sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
346 int status;
348 if (sdb_store_expr_eval(e1, obj, &v1, filter))
349 return INT_MAX;
350 if (sdb_store_expr_eval(e2, obj, &v2, filter)) {
351 sdb_data_free_datum(&v1);
352 return INT_MAX;
353 }
355 if (sdb_data_isnull(&v1) || (sdb_data_isnull(&v2)))
356 status = INT_MAX;
357 else if (v1.type == v2.type)
358 status = sdb_data_cmp(&v1, &v2);
359 else
360 status = sdb_data_strcmp(&v1, &v2);
362 sdb_data_free_datum(&v1);
363 sdb_data_free_datum(&v2);
364 return status;
365 } /* cmp_expr */
367 static int
368 match_cmp_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
369 sdb_store_matcher_t *filter)
370 {
371 int status;
372 assert(m->type == MATCHER_CMP_LT);
373 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
374 return (status != INT_MAX) && (status < 0);
375 } /* match_cmp_lt */
377 static int
378 match_cmp_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
379 sdb_store_matcher_t *filter)
380 {
381 int status;
382 assert(m->type == MATCHER_CMP_LE);
383 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
384 return (status != INT_MAX) && (status <= 0);
385 } /* match_cmp_le */
387 static int
388 match_cmp_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
389 sdb_store_matcher_t *filter)
390 {
391 int status;
392 assert(m->type == MATCHER_CMP_EQ);
393 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
394 return (status != INT_MAX) && (! status);
395 } /* match_cmp_eq */
397 static int
398 match_cmp_ne(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
399 sdb_store_matcher_t *filter)
400 {
401 int status;
402 assert(m->type == MATCHER_CMP_NE);
403 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
404 return (status != INT_MAX) && status;
405 } /* match_cmp_ne */
407 static int
408 match_cmp_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
409 sdb_store_matcher_t *filter)
410 {
411 int status;
412 assert(m->type == MATCHER_CMP_GE);
413 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
414 return (status != INT_MAX) && (status >= 0);
415 } /* match_cmp_ge */
417 static int
418 match_cmp_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
419 sdb_store_matcher_t *filter)
420 {
421 int status;
422 assert(m->type == MATCHER_CMP_GT);
423 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
424 return (status != INT_MAX) && (status > 0);
425 } /* match_cmp_gt */
427 static int
428 match_in(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
429 sdb_store_matcher_t *filter)
430 {
431 sdb_data_t value = SDB_DATA_INIT, array = SDB_DATA_INIT;
432 int status = 1;
434 assert(m->type == MATCHER_IN);
436 if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &value, filter))
437 || (sdb_store_expr_eval(CMP_M(m)->right, obj, &array, filter)))
438 status = 0;
440 if (status)
441 status = sdb_data_inarray(&value, &array);
443 sdb_data_free_datum(&value);
444 sdb_data_free_datum(&array);
445 return status;
446 } /* match_in */
448 static int
449 match_regex(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
450 sdb_store_matcher_t *filter)
451 {
452 sdb_data_t v = SDB_DATA_INIT;
453 int status = 0;
455 regex_t regex;
456 _Bool free_regex = 0;
458 assert((m->type == MATCHER_REGEX)
459 || (m->type == MATCHER_NREGEX));
461 if (! CMP_M(m)->right->type) {
462 assert(CMP_M(m)->right->data.type == SDB_TYPE_REGEX);
463 regex = CMP_M(m)->right->data.data.re.regex;
464 }
465 else {
466 sdb_data_t tmp = SDB_DATA_INIT;
467 char *raw;
469 if (sdb_store_expr_eval(CMP_M(m)->right, obj, &tmp, filter))
470 return 0;
472 if (tmp.type != SDB_TYPE_STRING) {
473 sdb_data_free_datum(&tmp);
474 return 0;
475 }
477 raw = tmp.data.string;
478 if (sdb_data_parse(raw, SDB_TYPE_REGEX, &tmp)) {
479 free(raw);
480 return 0;
481 }
483 regex = tmp.data.re.regex;
484 free_regex = 1;
485 free(tmp.data.re.raw);
486 free(raw);
487 }
489 if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &v, filter))
490 || (sdb_data_isnull(&v)))
491 status = 0;
492 else {
493 char value[sdb_data_strlen(&v) + 1];
494 if (sdb_data_format(&v, value, sizeof(value), SDB_UNQUOTED) < 0)
495 status = 0;
496 else if (! regexec(®ex, value, 0, NULL, 0))
497 status = 1;
498 }
500 if (free_regex)
501 regfree(®ex);
502 sdb_data_free_datum(&v);
503 if (m->type == MATCHER_NREGEX)
504 return !status;
505 return status;
506 } /* match_regex */
508 static int
509 match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
510 sdb_store_matcher_t *filter)
511 {
512 sdb_data_t v = SDB_DATA_INIT;
513 int status;
515 assert((m->type == MATCHER_ISNULL) || (m->type == MATCHER_ISNNULL));
517 /* TODO: this might hide real errors;
518 * improve error reporting and propagation */
519 if (sdb_store_expr_eval(ISNULL_M(m)->expr, obj, &v, filter)
520 || sdb_data_isnull(&v))
521 status = 1;
522 else
523 status = 0;
525 sdb_data_free_datum(&v);
526 if (m->type == MATCHER_ISNNULL)
527 return !status;
528 return status;
529 } /* match_isnull */
531 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_obj_t *,
532 sdb_store_matcher_t *);
534 /* this array needs to be indexable by the matcher types;
535 * -> update the enum in store-private.h when updating this */
536 static matcher_cb
537 matchers[] = {
538 match_logical,
539 match_logical,
540 match_unary,
541 match_name,
542 match_attr,
543 match_child,
544 match_child,
545 match_child,
546 match_lt,
547 match_le,
548 match_eq,
549 match_ge,
550 match_gt,
551 match_cmp_lt,
552 match_cmp_le,
553 match_cmp_eq,
554 match_cmp_ne,
555 match_cmp_ge,
556 match_cmp_gt,
557 match_in,
558 match_regex,
559 match_regex,
560 match_isnull,
561 match_isnull,
562 };
564 /*
565 * private conditional types
566 */
568 static int
569 attr_cond_init(sdb_object_t *obj, va_list ap)
570 {
571 const char *name = va_arg(ap, const char *);
572 sdb_store_expr_t *expr = va_arg(ap, sdb_store_expr_t *);
574 if (! name)
575 return -1;
577 SDB_STORE_COND(obj)->cmp = attr_cmp;
579 ATTR_C(obj)->name = strdup(name);
580 if (! ATTR_C(obj)->name)
581 return -1;
582 ATTR_C(obj)->expr = expr;
583 sdb_object_ref(SDB_OBJ(expr));
584 return 0;
585 } /* attr_cond_init */
587 static void
588 attr_cond_destroy(sdb_object_t *obj)
589 {
590 if (ATTR_C(obj)->name)
591 free(ATTR_C(obj)->name);
592 sdb_object_deref(SDB_OBJ(ATTR_C(obj)->expr));
593 } /* attr_cond_destroy */
595 static sdb_type_t attr_cond_type = {
596 /* size = */ sizeof(attr_cond_t),
597 /* init = */ attr_cond_init,
598 /* destroy = */ attr_cond_destroy,
599 };
601 /*
602 * private matcher types
603 */
605 /* initializes a string matcher consuming two elements from ap */
606 static int
607 string_matcher_init(string_matcher_t *m, va_list ap)
608 {
609 const char *name = va_arg(ap, const char *);
610 const char *name_re = va_arg(ap, const char *);
612 if (name) {
613 m->name = strdup(name);
614 if (! m->name)
615 return -1;
616 }
617 if (name_re) {
618 m->name_re = malloc(sizeof(*m->name_re));
619 if (! m->name_re)
620 return -1;
621 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
622 return -1;
623 }
624 return 0;
625 } /* string_matcher_init */
627 static void
628 string_matcher_destroy(string_matcher_t *m)
629 {
630 if (m->name)
631 free(m->name);
632 if (m->name_re) {
633 regfree(m->name_re);
634 free(m->name_re);
635 }
636 } /* string_matcher_destroy */
638 /* initializes a name matcher */
639 static int
640 name_matcher_init(sdb_object_t *obj, va_list ap)
641 {
642 name_matcher_t *m = NAME_M(obj);
643 M(obj)->type = MATCHER_NAME;
644 return string_matcher_init(&m->name, ap);
645 } /* name_matcher_init */
647 static void
648 name_matcher_destroy(sdb_object_t *obj)
649 {
650 name_matcher_t *m = NAME_M(obj);
651 string_matcher_destroy(&m->name);
652 } /* name_matcher_destroy */
654 static int
655 attr_matcher_init(sdb_object_t *obj, va_list ap)
656 {
657 attr_matcher_t *attr = ATTR_M(obj);
658 const char *name = va_arg(ap, const char *);
660 M(obj)->type = MATCHER_ATTR;
661 if (name) {
662 attr->name = strdup(name);
663 if (! attr->name)
664 return -1;
665 }
666 return string_matcher_init(&attr->value, ap);
667 } /* attr_matcher_init */
669 static void
670 attr_matcher_destroy(sdb_object_t *obj)
671 {
672 attr_matcher_t *attr = ATTR_M(obj);
673 if (attr->name)
674 free(attr->name);
675 attr->name = NULL;
676 string_matcher_destroy(&attr->value);
677 } /* attr_matcher_destroy */
679 static int
680 cond_matcher_init(sdb_object_t *obj, va_list ap)
681 {
682 int type = va_arg(ap, int);
683 sdb_store_cond_t *cond = va_arg(ap, sdb_store_cond_t *);
685 if (! cond)
686 return -1;
688 sdb_object_ref(SDB_OBJ(cond));
690 M(obj)->type = type;
691 COND_M(obj)->cond = cond;
692 return 0;
693 } /* cond_matcher_init */
695 static void
696 cond_matcher_destroy(sdb_object_t *obj)
697 {
698 sdb_object_deref(SDB_OBJ(COND_M(obj)->cond));
699 } /* cond_matcher_destroy */
701 static int
702 op_matcher_init(sdb_object_t *obj, va_list ap)
703 {
704 M(obj)->type = va_arg(ap, int);
705 if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
706 return -1;
708 OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
709 sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
710 OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
711 sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
713 if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
714 return -1;
715 return 0;
716 } /* op_matcher_init */
718 static void
719 op_matcher_destroy(sdb_object_t *obj)
720 {
721 if (OP_M(obj)->left)
722 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
723 if (OP_M(obj)->right)
724 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
725 } /* op_matcher_destroy */
727 static int
728 child_matcher_init(sdb_object_t *obj, va_list ap)
729 {
730 M(obj)->type = va_arg(ap, int);
731 CHILD_M(obj)->m = va_arg(ap, sdb_store_matcher_t *);
733 if (! CHILD_M(obj)->m)
734 return -1;
736 sdb_object_ref(SDB_OBJ(CHILD_M(obj)->m));
737 return 0;
738 } /* child_matcher_init */
740 static void
741 child_matcher_destroy(sdb_object_t *obj)
742 {
743 sdb_object_deref(SDB_OBJ(CHILD_M(obj)->m));
744 } /* child_matcher_destroy */
746 static int
747 cmp_matcher_init(sdb_object_t *obj, va_list ap)
748 {
749 M(obj)->type = va_arg(ap, int);
751 CMP_M(obj)->left = va_arg(ap, sdb_store_expr_t *);
752 sdb_object_ref(SDB_OBJ(CMP_M(obj)->left));
753 CMP_M(obj)->right = va_arg(ap, sdb_store_expr_t *);
754 sdb_object_ref(SDB_OBJ(CMP_M(obj)->right));
756 if ((! CMP_M(obj)->left) || (! CMP_M(obj)->right))
757 return -1;
758 return 0;
759 } /* cmp_matcher_init */
761 static void
762 cmp_matcher_destroy(sdb_object_t *obj)
763 {
764 sdb_object_deref(SDB_OBJ(CMP_M(obj)->left));
765 sdb_object_deref(SDB_OBJ(CMP_M(obj)->right));
766 } /* cmp_matcher_destroy */
768 static int
769 uop_matcher_init(sdb_object_t *obj, va_list ap)
770 {
771 M(obj)->type = va_arg(ap, int);
772 if (M(obj)->type != MATCHER_NOT)
773 return -1;
775 UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
776 sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
778 if (! UOP_M(obj)->op)
779 return -1;
780 return 0;
781 } /* uop_matcher_init */
783 static void
784 uop_matcher_destroy(sdb_object_t *obj)
785 {
786 if (UOP_M(obj)->op)
787 sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
788 } /* uop_matcher_destroy */
790 static int
791 isnull_matcher_init(sdb_object_t *obj, va_list ap)
792 {
793 M(obj)->type = va_arg(ap, int);
794 if ((M(obj)->type != MATCHER_ISNULL) && (M(obj)->type != MATCHER_ISNNULL))
795 return -1;
797 ISNULL_M(obj)->expr = va_arg(ap, sdb_store_expr_t *);
798 sdb_object_ref(SDB_OBJ(ISNULL_M(obj)->expr));
799 return 0;
800 } /* isnull_matcher_init */
802 static void
803 isnull_matcher_destroy(sdb_object_t *obj)
804 {
805 sdb_object_deref(SDB_OBJ(ISNULL_M(obj)->expr));
806 ISNULL_M(obj)->expr = NULL;
807 } /* isnull_matcher_destroy */
809 static sdb_type_t name_type = {
810 /* size = */ sizeof(name_matcher_t),
811 /* init = */ name_matcher_init,
812 /* destroy = */ name_matcher_destroy,
813 };
815 static sdb_type_t attr_type = {
816 /* size = */ sizeof(attr_matcher_t),
817 /* init = */ attr_matcher_init,
818 /* destroy = */ attr_matcher_destroy,
819 };
821 static sdb_type_t cond_type = {
822 /* size = */ sizeof(cond_matcher_t),
823 /* init = */ cond_matcher_init,
824 /* destroy = */ cond_matcher_destroy,
825 };
827 static sdb_type_t op_type = {
828 /* size = */ sizeof(op_matcher_t),
829 /* init = */ op_matcher_init,
830 /* destroy = */ op_matcher_destroy,
831 };
833 static sdb_type_t uop_type = {
834 /* size = */ sizeof(uop_matcher_t),
835 /* init = */ uop_matcher_init,
836 /* destroy = */ uop_matcher_destroy,
837 };
839 static sdb_type_t child_type = {
840 /* size = */ sizeof(child_matcher_t),
841 /* init = */ child_matcher_init,
842 /* destroy = */ child_matcher_destroy,
843 };
845 static sdb_type_t cmp_type = {
846 /* size = */ sizeof(cmp_matcher_t),
847 /* init = */ cmp_matcher_init,
848 /* destroy = */ cmp_matcher_destroy,
849 };
851 static sdb_type_t isnull_type = {
852 /* size = */ sizeof(isnull_matcher_t),
853 /* init = */ isnull_matcher_init,
854 /* destroy = */ isnull_matcher_destroy,
855 };
857 /*
858 * public API
859 */
861 sdb_store_cond_t *
862 sdb_store_attr_cond(const char *name, sdb_store_expr_t *expr)
863 {
864 return SDB_STORE_COND(sdb_object_create("attr-cond", attr_cond_type,
865 name, expr));
866 } /* sdb_store_attr_cond */
868 sdb_store_matcher_t *
869 sdb_store_name_matcher(int type, const char *name, _Bool re)
870 {
871 sdb_store_matcher_t *m;
873 if (re)
874 m = M(sdb_object_create("name-matcher", name_type, NULL, name));
875 else
876 m = M(sdb_object_create("name-matcher", name_type, name, NULL));
878 if (! m)
879 return NULL;
881 NAME_M(m)->obj_type = type;
882 return m;
883 } /* sdb_store_name_matcher */
885 sdb_store_matcher_t *
886 sdb_store_attr_matcher(const char *name, const char *value, _Bool re)
887 {
888 sdb_store_matcher_t *m;
890 if (! name)
891 return NULL;
893 if (re)
894 m = M(sdb_object_create("attr-matcher", attr_type,
895 name, NULL, value));
896 else
897 m = M(sdb_object_create("attr-matcher", attr_type,
898 name, value, NULL));
899 return m;
900 } /* sdb_store_attr_matcher */
902 sdb_store_matcher_t *
903 sdb_store_child_matcher(int type, sdb_store_matcher_t *m)
904 {
905 if (type == SDB_SERVICE)
906 type = MATCHER_SERVICE;
907 else if (type == SDB_METRIC)
908 type = MATCHER_METRIC;
909 else if (type == SDB_ATTRIBUTE)
910 type = MATCHER_ATTRIBUTE;
911 else
912 return NULL;
913 return M(sdb_object_create("any-matcher", child_type, type, m));
914 } /* sdb_store_child_matcher */
916 sdb_store_matcher_t *
917 sdb_store_lt_matcher(sdb_store_cond_t *cond)
918 {
919 return M(sdb_object_create("lt-matcher", cond_type,
920 MATCHER_LT, cond));
921 } /* sdb_store_lt_matcher */
923 sdb_store_matcher_t *
924 sdb_store_le_matcher(sdb_store_cond_t *cond)
925 {
926 return M(sdb_object_create("le-matcher", cond_type,
927 MATCHER_LE, cond));
928 } /* sdb_store_le_matcher */
930 sdb_store_matcher_t *
931 sdb_store_eq_matcher(sdb_store_cond_t *cond)
932 {
933 return M(sdb_object_create("eq-matcher", cond_type,
934 MATCHER_EQ, cond));
935 } /* sdb_store_eq_matcher */
937 sdb_store_matcher_t *
938 sdb_store_ge_matcher(sdb_store_cond_t *cond)
939 {
940 return M(sdb_object_create("ge-matcher", cond_type,
941 MATCHER_GE, cond));
942 } /* sdb_store_ge_matcher */
944 sdb_store_matcher_t *
945 sdb_store_gt_matcher(sdb_store_cond_t *cond)
946 {
947 return M(sdb_object_create("gt-matcher", cond_type,
948 MATCHER_GT, cond));
949 } /* sdb_store_gt_matcher */
951 /*
952 * TODO: Rename sdb_store_cmp_* to sdb_store_* once the old code is unused and
953 * has been removed.
954 */
956 sdb_store_matcher_t *
957 sdb_store_cmp_lt(sdb_store_expr_t *left, sdb_store_expr_t *right)
958 {
959 return M(sdb_object_create("lt-matcher", cmp_type,
960 MATCHER_CMP_LT, left, right));
961 } /* sdb_store_cmp_lt */
963 sdb_store_matcher_t *
964 sdb_store_cmp_le(sdb_store_expr_t *left, sdb_store_expr_t *right)
965 {
966 return M(sdb_object_create("le-matcher", cmp_type,
967 MATCHER_CMP_LE, left, right));
968 } /* sdb_store_cmp_le */
970 sdb_store_matcher_t *
971 sdb_store_cmp_eq(sdb_store_expr_t *left, sdb_store_expr_t *right)
972 {
973 return M(sdb_object_create("eq-matcher", cmp_type,
974 MATCHER_CMP_EQ, left, right));
975 } /* sdb_store_cmp_eq */
977 sdb_store_matcher_t *
978 sdb_store_cmp_ne(sdb_store_expr_t *left, sdb_store_expr_t *right)
979 {
980 return M(sdb_object_create("ne-matcher", cmp_type,
981 MATCHER_CMP_NE, left, right));
982 } /* sdb_store_cmp_ne */
984 sdb_store_matcher_t *
985 sdb_store_cmp_ge(sdb_store_expr_t *left, sdb_store_expr_t *right)
986 {
987 return M(sdb_object_create("ge-matcher", cmp_type,
988 MATCHER_CMP_GE, left, right));
989 } /* sdb_store_cmp_ge */
991 sdb_store_matcher_t *
992 sdb_store_cmp_gt(sdb_store_expr_t *left, sdb_store_expr_t *right)
993 {
994 return M(sdb_object_create("gt-matcher", cmp_type,
995 MATCHER_CMP_GT, left, right));
996 } /* sdb_store_cmp_gt */
998 sdb_store_matcher_t *
999 sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
1000 {
1001 return M(sdb_object_create("in-matcher", cmp_type,
1002 MATCHER_IN, left, right));
1003 } /* sdb_store_in_matcher */
1005 sdb_store_matcher_t *
1006 sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
1007 {
1008 if (! right->type) {
1009 if ((right->data.type != SDB_TYPE_STRING)
1010 && (right->data.type != SDB_TYPE_REGEX))
1011 return NULL;
1013 if (right->data.type == SDB_TYPE_STRING) {
1014 char *raw = right->data.data.string;
1015 if (sdb_data_parse(raw, SDB_TYPE_REGEX, &right->data))
1016 return NULL;
1017 free(raw);
1018 }
1019 }
1020 return M(sdb_object_create("regex-matcher", cmp_type,
1021 MATCHER_REGEX, left, right));
1022 } /* sdb_store_regex_matcher */
1024 sdb_store_matcher_t *
1025 sdb_store_nregex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
1026 {
1027 sdb_store_matcher_t *m = sdb_store_regex_matcher(left, right);
1028 if (! m)
1029 return NULL;
1030 m->type = MATCHER_NREGEX;
1031 return m;
1032 } /* sdb_store_nregex_matcher */
1034 sdb_store_matcher_t *
1035 sdb_store_isnull_matcher(sdb_store_expr_t *expr)
1036 {
1037 return M(sdb_object_create("isnull-matcher", isnull_type,
1038 MATCHER_ISNULL, expr));
1039 } /* sdb_store_isnull_matcher */
1041 sdb_store_matcher_t *
1042 sdb_store_isnnull_matcher(sdb_store_expr_t *expr)
1043 {
1044 return M(sdb_object_create("isnull-matcher", isnull_type,
1045 MATCHER_ISNNULL, expr));
1046 } /* sdb_store_isnnull_matcher */
1048 sdb_store_matcher_op_cb
1049 sdb_store_parse_matcher_op(const char *op)
1050 {
1051 if (! strcasecmp(op, "<"))
1052 return sdb_store_cmp_lt;
1053 else if (! strcasecmp(op, "<="))
1054 return sdb_store_cmp_le;
1055 else if (! strcasecmp(op, "="))
1056 return sdb_store_cmp_eq;
1057 else if (! strcasecmp(op, "!="))
1058 return sdb_store_cmp_ne;
1059 else if (! strcasecmp(op, ">="))
1060 return sdb_store_cmp_ge;
1061 else if (! strcasecmp(op, ">"))
1062 return sdb_store_cmp_gt;
1063 else if (! strcasecmp(op, "=~"))
1064 return sdb_store_regex_matcher;
1065 else if (! strcasecmp(op, "!~"))
1066 return sdb_store_nregex_matcher;
1067 return NULL;
1068 } /* sdb_store_parse_matcher_op */
1070 int
1071 sdb_store_parse_object_type_plural(const char *name)
1072 {
1073 if (! strcasecmp(name, "hosts"))
1074 return SDB_HOST;
1075 else if (! strcasecmp(name, "services"))
1076 return SDB_SERVICE;
1077 else if (! strcasecmp(name, "metrics"))
1078 return SDB_METRIC;
1079 return -1;
1080 } /* sdb_store_parse_object_type_plural */
1082 int
1083 sdb_store_parse_field_name(const char *name)
1084 {
1085 if (! strcasecmp(name, "name"))
1086 return SDB_FIELD_NAME;
1087 else if (! strcasecmp(name, "last_update"))
1088 return SDB_FIELD_LAST_UPDATE;
1089 else if (! strcasecmp(name, "age"))
1090 return SDB_FIELD_AGE;
1091 else if (! strcasecmp(name, "interval"))
1092 return SDB_FIELD_INTERVAL;
1093 else if (! strcasecmp(name, "backend"))
1094 return SDB_FIELD_BACKEND;
1095 return -1;
1096 } /* sdb_store_parse_field_name */
1098 static sdb_store_matcher_t *
1099 maybe_inv_matcher(sdb_store_matcher_t *m, _Bool inv)
1100 {
1101 sdb_store_matcher_t *tmp;
1103 if ((! m) || (! inv))
1104 return m;
1106 tmp = sdb_store_inv_matcher(m);
1107 /* pass ownership to the inverse matcher */
1108 sdb_object_deref(SDB_OBJ(m));
1109 return tmp;
1110 } /* maybe_inv_matcher */
1112 static int
1113 parse_cond_op(const char *op,
1114 sdb_store_matcher_t *(**matcher)(sdb_store_cond_t *), _Bool *inv)
1115 {
1116 *inv = 0;
1117 if (! strcasecmp(op, "<"))
1118 *matcher = sdb_store_lt_matcher;
1119 else if (! strcasecmp(op, "<="))
1120 *matcher = sdb_store_le_matcher;
1121 else if (! strcasecmp(op, "="))
1122 *matcher = sdb_store_eq_matcher;
1123 else if (! strcasecmp(op, ">="))
1124 *matcher = sdb_store_ge_matcher;
1125 else if (! strcasecmp(op, ">"))
1126 *matcher = sdb_store_gt_matcher;
1127 else if (! strcasecmp(op, "!=")) {
1128 *matcher = sdb_store_eq_matcher;
1129 *inv = 1;
1130 }
1131 else
1132 return -1;
1133 return 0;
1134 } /* parse_cond_op */
1136 static sdb_store_matcher_t *
1137 parse_attr_cmp(const char *attr, const char *op, sdb_store_expr_t *expr)
1138 {
1139 sdb_store_matcher_t *(*matcher)(sdb_store_cond_t *) = NULL;
1140 sdb_store_matcher_t *m;
1141 sdb_store_cond_t *cond;
1142 _Bool inv = 0;
1144 if (! attr)
1145 return NULL;
1147 if (! expr)
1148 return NULL;
1149 else if (parse_cond_op(op, &matcher, &inv))
1150 return NULL;
1152 cond = sdb_store_attr_cond(attr, expr);
1153 if (! cond)
1154 return NULL;
1156 m = matcher(cond);
1157 /* pass ownership to 'm' or destroy in case of an error */
1158 sdb_object_deref(SDB_OBJ(cond));
1159 return maybe_inv_matcher(m, inv);
1160 } /* parse_attr_cmp */
1162 sdb_store_matcher_t *
1163 sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr,
1164 const char *op, sdb_store_expr_t *expr)
1165 {
1166 int type = -1;
1167 _Bool inv = 0;
1168 _Bool re = 0;
1170 sdb_data_t value = SDB_DATA_INIT;
1171 sdb_store_matcher_t *m = NULL;
1173 if (! strcasecmp(obj_type, "host"))
1174 type = SDB_HOST;
1175 else if (! strcasecmp(obj_type, "service"))
1176 type = SDB_SERVICE;
1177 else if (! strcasecmp(obj_type, "metric"))
1178 type = SDB_METRIC;
1179 else if (! strcasecmp(obj_type, "attribute"))
1180 type = SDB_ATTRIBUTE;
1181 else
1182 return NULL;
1184 /* XXX: this code sucks! */
1185 if (! strcasecmp(op, "=")) {
1186 /* nothing to do */
1187 }
1188 else if (! strcasecmp(op, "!=")) {
1189 inv = 1;
1190 }
1191 else if (! strcasecmp(op, "=~")) {
1192 re = 1;
1193 }
1194 else if (! strcasecmp(op, "!~")) {
1195 inv = 1;
1196 re = 1;
1197 }
1198 else if (type == SDB_ATTRIBUTE)
1199 return parse_attr_cmp(attr, op, expr);
1200 else
1201 return NULL;
1203 if (! expr)
1204 return NULL;
1206 if (sdb_store_expr_eval(expr, /* obj */ NULL, &value, /* filter */ NULL)
1207 || (value.type != SDB_TYPE_STRING)) {
1208 sdb_data_free_datum(&value);
1209 if (type != SDB_ATTRIBUTE)
1210 return NULL;
1211 return parse_attr_cmp(attr, op, expr);
1212 }
1214 if (! attr)
1215 m = sdb_store_name_matcher(type, value.data.string, re);
1216 else if (type == SDB_ATTRIBUTE)
1217 m = sdb_store_attr_matcher(attr, value.data.string, re);
1219 sdb_data_free_datum(&value);
1220 return maybe_inv_matcher(m, inv);
1221 } /* sdb_store_matcher_parse_cmp */
1223 sdb_store_matcher_t *
1224 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
1225 {
1226 return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
1227 left, right));
1228 } /* sdb_store_dis_matcher */
1230 sdb_store_matcher_t *
1231 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
1232 {
1233 return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
1234 left, right));
1235 } /* sdb_store_con_matcher */
1237 sdb_store_matcher_t *
1238 sdb_store_inv_matcher(sdb_store_matcher_t *m)
1239 {
1240 return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
1241 } /* sdb_store_inv_matcher */
1243 int
1244 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
1245 sdb_store_matcher_t *filter)
1246 {
1247 if (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))
1248 return 0;
1250 /* "NULL" always matches */
1251 if ((! m) || (! obj))
1252 return 1;
1254 if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
1255 return 0;
1257 return matchers[m->type](m, obj, filter);
1258 } /* sdb_store_matcher_matches */
1260 int
1261 sdb_store_scan(sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
1262 sdb_store_lookup_cb cb, void *user_data)
1263 {
1264 scan_iter_data_t data = { m, filter, cb, user_data };
1266 if (! cb)
1267 return -1;
1268 return sdb_store_iterate(scan_iter, &data);
1269 } /* sdb_store_scan */
1271 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */