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 /*
78 * matcher implementations
79 */
81 static int
82 match_string(string_matcher_t *m, const char *name)
83 {
84 if ((! m->name) && (! m->name_re))
85 return 1;
87 if (! name)
88 name = "";
90 if (m->name && strcasecmp(m->name, name))
91 return 0;
92 if (m->name_re && regexec(m->name_re, name,
93 /* matches */ 0, NULL, /* flags = */ 0))
94 return 0;
95 return 1;
96 } /* match_string */
98 static int
99 match_logical(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
100 sdb_store_matcher_t *filter)
101 {
102 int status;
104 assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
105 assert(OP_M(m)->left && OP_M(m)->right);
107 status = sdb_store_matcher_matches(OP_M(m)->left, obj, filter);
109 /* lazy evaluation */
110 if ((! status) && (m->type == MATCHER_AND))
111 return status;
112 else if (status && (m->type == MATCHER_OR))
113 return status;
115 return sdb_store_matcher_matches(OP_M(m)->right, obj, filter);
116 } /* match_logical */
118 static int
119 match_unary(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
120 sdb_store_matcher_t *filter)
121 {
122 assert(m->type == MATCHER_NOT);
123 assert(UOP_M(m)->op);
125 return !sdb_store_matcher_matches(UOP_M(m)->op, obj, filter);
126 } /* match_unary */
128 static int
129 match_name(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
130 sdb_store_matcher_t *filter)
131 {
132 sdb_avltree_iter_t *iter = NULL;
133 int status = 0;
135 assert(m->type == MATCHER_NAME);
137 if (obj->type == NAME_M(m)->obj_type)
138 return match_string(&NAME_M(m)->name, SDB_OBJ(obj)->name);
139 else if (obj->type != SDB_HOST)
140 return 0;
142 switch (NAME_M(m)->obj_type) {
143 case SDB_SERVICE:
144 iter = sdb_avltree_get_iter(HOST(obj)->services);
145 break;
146 case SDB_METRIC:
147 iter = sdb_avltree_get_iter(HOST(obj)->metrics);
148 break;
149 case SDB_ATTRIBUTE:
150 iter = sdb_avltree_get_iter(HOST(obj)->attributes);
151 break;
152 }
154 while (sdb_avltree_iter_has_next(iter)) {
155 sdb_object_t *child = sdb_avltree_iter_get_next(iter);
156 if (filter && (! sdb_store_matcher_matches(filter, STORE_OBJ(child),
157 NULL)))
158 continue;
159 if (match_string(&NAME_M(m)->name, child->name)) {
160 status = 1;
161 break;
162 }
163 }
164 sdb_avltree_iter_destroy(iter);
165 return status;
166 } /* match_name */
168 static int
169 match_child(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
170 sdb_store_matcher_t *filter)
171 {
172 sdb_avltree_iter_t *iter = NULL;
173 int status = 0;
175 assert((m->type == MATCHER_SERVICE)
176 || (m->type == MATCHER_METRIC)
177 || (m->type == MATCHER_ATTRIBUTE));
179 /* TODO: support all object types */
180 if (obj->type != SDB_HOST)
181 return 0;
183 if (m->type == MATCHER_SERVICE)
184 iter = sdb_avltree_get_iter(HOST(obj)->services);
185 else if (m->type == MATCHER_METRIC)
186 iter = sdb_avltree_get_iter(HOST(obj)->metrics);
187 else if (m->type == MATCHER_ATTRIBUTE)
188 iter = sdb_avltree_get_iter(HOST(obj)->attributes);
190 while (sdb_avltree_iter_has_next(iter)) {
191 sdb_store_obj_t *child = STORE_OBJ(sdb_avltree_iter_get_next(iter));
192 if (filter && (! sdb_store_matcher_matches(filter, child, NULL)))
193 continue;
195 if (sdb_store_matcher_matches(CHILD_M(m)->m, child, filter)) {
196 status = 1;
197 break;
198 }
199 }
200 sdb_avltree_iter_destroy(iter);
201 return status;
202 } /* match_child */
204 /*
205 * cmp_expr:
206 * Compare the values of two expressions when evaluating them using the
207 * specified stored object and filter. Returns a value less than, equal to, or
208 * greater than zero if the value of the first expression compares less than,
209 * equal to, or greater than the value of the second expression. Returns
210 * INT_MAX if any of the expressions could not be evaluated or if any of them
211 * evaluated to NULL.
212 */
213 static int
214 cmp_expr(sdb_store_expr_t *e1, sdb_store_expr_t *e2,
215 sdb_store_obj_t *obj, sdb_store_matcher_t *filter)
216 {
217 sdb_data_t v1 = SDB_DATA_INIT, v2 = SDB_DATA_INIT;
218 int status;
220 if (sdb_store_expr_eval(e1, obj, &v1, filter))
221 return INT_MAX;
222 if (sdb_store_expr_eval(e2, obj, &v2, filter)) {
223 sdb_data_free_datum(&v1);
224 return INT_MAX;
225 }
227 if (sdb_data_isnull(&v1) || (sdb_data_isnull(&v2)))
228 status = INT_MAX;
229 else if (v1.type == v2.type)
230 status = sdb_data_cmp(&v1, &v2);
231 else
232 status = sdb_data_strcmp(&v1, &v2);
234 sdb_data_free_datum(&v1);
235 sdb_data_free_datum(&v2);
236 return status;
237 } /* cmp_expr */
239 static int
240 match_lt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
241 sdb_store_matcher_t *filter)
242 {
243 int status;
244 assert(m->type == MATCHER_LT);
245 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
246 return (status != INT_MAX) && (status < 0);
247 } /* match_lt */
249 static int
250 match_le(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
251 sdb_store_matcher_t *filter)
252 {
253 int status;
254 assert(m->type == MATCHER_LE);
255 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
256 return (status != INT_MAX) && (status <= 0);
257 } /* match_le */
259 static int
260 match_eq(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
261 sdb_store_matcher_t *filter)
262 {
263 int status;
264 assert(m->type == MATCHER_EQ);
265 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
266 return (status != INT_MAX) && (! status);
267 } /* match_eq */
269 static int
270 match_ne(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
271 sdb_store_matcher_t *filter)
272 {
273 int status;
274 assert(m->type == MATCHER_NE);
275 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
276 return (status != INT_MAX) && status;
277 } /* match_ne */
279 static int
280 match_ge(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
281 sdb_store_matcher_t *filter)
282 {
283 int status;
284 assert(m->type == MATCHER_GE);
285 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
286 return (status != INT_MAX) && (status >= 0);
287 } /* match_ge */
289 static int
290 match_gt(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
291 sdb_store_matcher_t *filter)
292 {
293 int status;
294 assert(m->type == MATCHER_GT);
295 status = cmp_expr(CMP_M(m)->left, CMP_M(m)->right, obj, filter);
296 return (status != INT_MAX) && (status > 0);
297 } /* match_gt */
299 static int
300 match_in(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
301 sdb_store_matcher_t *filter)
302 {
303 sdb_data_t value = SDB_DATA_INIT, array = SDB_DATA_INIT;
304 int status = 1;
306 assert(m->type == MATCHER_IN);
308 if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &value, filter))
309 || (sdb_store_expr_eval(CMP_M(m)->right, obj, &array, filter)))
310 status = 0;
312 if (status)
313 status = sdb_data_inarray(&value, &array);
315 sdb_data_free_datum(&value);
316 sdb_data_free_datum(&array);
317 return status;
318 } /* match_in */
320 static int
321 match_regex(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
322 sdb_store_matcher_t *filter)
323 {
324 sdb_data_t v = SDB_DATA_INIT;
325 int status = 0;
327 regex_t regex;
328 _Bool free_regex = 0;
330 assert((m->type == MATCHER_REGEX)
331 || (m->type == MATCHER_NREGEX));
333 if (! CMP_M(m)->right->type) {
334 assert(CMP_M(m)->right->data.type == SDB_TYPE_REGEX);
335 regex = CMP_M(m)->right->data.data.re.regex;
336 }
337 else {
338 sdb_data_t tmp = SDB_DATA_INIT;
339 char *raw;
341 if (sdb_store_expr_eval(CMP_M(m)->right, obj, &tmp, filter))
342 return 0;
344 if (tmp.type != SDB_TYPE_STRING) {
345 sdb_data_free_datum(&tmp);
346 return 0;
347 }
349 raw = tmp.data.string;
350 if (sdb_data_parse(raw, SDB_TYPE_REGEX, &tmp)) {
351 free(raw);
352 return 0;
353 }
355 regex = tmp.data.re.regex;
356 free_regex = 1;
357 free(tmp.data.re.raw);
358 free(raw);
359 }
361 if ((sdb_store_expr_eval(CMP_M(m)->left, obj, &v, filter))
362 || (sdb_data_isnull(&v)))
363 status = 0;
364 else {
365 char value[sdb_data_strlen(&v) + 1];
366 if (sdb_data_format(&v, value, sizeof(value), SDB_UNQUOTED) < 0)
367 status = 0;
368 else if (! regexec(®ex, value, 0, NULL, 0))
369 status = 1;
370 }
372 if (free_regex)
373 regfree(®ex);
374 sdb_data_free_datum(&v);
375 if (m->type == MATCHER_NREGEX)
376 return !status;
377 return status;
378 } /* match_regex */
380 static int
381 match_isnull(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
382 sdb_store_matcher_t *filter)
383 {
384 sdb_data_t v = SDB_DATA_INIT;
385 int status;
387 assert((m->type == MATCHER_ISNULL) || (m->type == MATCHER_ISNNULL));
389 /* TODO: this might hide real errors;
390 * improve error reporting and propagation */
391 if (sdb_store_expr_eval(ISNULL_M(m)->expr, obj, &v, filter)
392 || sdb_data_isnull(&v))
393 status = 1;
394 else
395 status = 0;
397 sdb_data_free_datum(&v);
398 if (m->type == MATCHER_ISNNULL)
399 return !status;
400 return status;
401 } /* match_isnull */
403 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_obj_t *,
404 sdb_store_matcher_t *);
406 /* this array needs to be indexable by the matcher types;
407 * -> update the enum in store-private.h when updating this */
408 static matcher_cb
409 matchers[] = {
410 match_logical,
411 match_logical,
412 match_unary,
413 match_name,
414 match_child,
415 match_child,
416 match_child,
417 match_lt,
418 match_le,
419 match_eq,
420 match_ne,
421 match_ge,
422 match_gt,
423 match_in,
424 match_regex,
425 match_regex,
426 match_isnull,
427 match_isnull,
428 };
430 /*
431 * private matcher types
432 */
434 /* initializes a string matcher consuming two elements from ap */
435 static int
436 string_matcher_init(string_matcher_t *m, va_list ap)
437 {
438 const char *name = va_arg(ap, const char *);
439 const char *name_re = va_arg(ap, const char *);
441 if (name) {
442 m->name = strdup(name);
443 if (! m->name)
444 return -1;
445 }
446 if (name_re) {
447 m->name_re = malloc(sizeof(*m->name_re));
448 if (! m->name_re)
449 return -1;
450 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
451 return -1;
452 }
453 return 0;
454 } /* string_matcher_init */
456 static void
457 string_matcher_destroy(string_matcher_t *m)
458 {
459 if (m->name)
460 free(m->name);
461 if (m->name_re) {
462 regfree(m->name_re);
463 free(m->name_re);
464 }
465 } /* string_matcher_destroy */
467 /* initializes a name matcher */
468 static int
469 name_matcher_init(sdb_object_t *obj, va_list ap)
470 {
471 name_matcher_t *m = NAME_M(obj);
472 M(obj)->type = MATCHER_NAME;
473 return string_matcher_init(&m->name, ap);
474 } /* name_matcher_init */
476 static void
477 name_matcher_destroy(sdb_object_t *obj)
478 {
479 name_matcher_t *m = NAME_M(obj);
480 string_matcher_destroy(&m->name);
481 } /* name_matcher_destroy */
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 int
510 child_matcher_init(sdb_object_t *obj, va_list ap)
511 {
512 M(obj)->type = va_arg(ap, int);
513 CHILD_M(obj)->m = va_arg(ap, sdb_store_matcher_t *);
515 if (! CHILD_M(obj)->m)
516 return -1;
518 sdb_object_ref(SDB_OBJ(CHILD_M(obj)->m));
519 return 0;
520 } /* child_matcher_init */
522 static void
523 child_matcher_destroy(sdb_object_t *obj)
524 {
525 sdb_object_deref(SDB_OBJ(CHILD_M(obj)->m));
526 } /* child_matcher_destroy */
528 static int
529 cmp_matcher_init(sdb_object_t *obj, va_list ap)
530 {
531 M(obj)->type = va_arg(ap, int);
533 CMP_M(obj)->left = va_arg(ap, sdb_store_expr_t *);
534 sdb_object_ref(SDB_OBJ(CMP_M(obj)->left));
535 CMP_M(obj)->right = va_arg(ap, sdb_store_expr_t *);
536 sdb_object_ref(SDB_OBJ(CMP_M(obj)->right));
538 if ((! CMP_M(obj)->left) || (! CMP_M(obj)->right))
539 return -1;
540 return 0;
541 } /* cmp_matcher_init */
543 static void
544 cmp_matcher_destroy(sdb_object_t *obj)
545 {
546 sdb_object_deref(SDB_OBJ(CMP_M(obj)->left));
547 sdb_object_deref(SDB_OBJ(CMP_M(obj)->right));
548 } /* cmp_matcher_destroy */
550 static int
551 uop_matcher_init(sdb_object_t *obj, va_list ap)
552 {
553 M(obj)->type = va_arg(ap, int);
554 if (M(obj)->type != MATCHER_NOT)
555 return -1;
557 UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
558 sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
560 if (! UOP_M(obj)->op)
561 return -1;
562 return 0;
563 } /* uop_matcher_init */
565 static void
566 uop_matcher_destroy(sdb_object_t *obj)
567 {
568 if (UOP_M(obj)->op)
569 sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
570 } /* uop_matcher_destroy */
572 static int
573 isnull_matcher_init(sdb_object_t *obj, va_list ap)
574 {
575 M(obj)->type = va_arg(ap, int);
576 if ((M(obj)->type != MATCHER_ISNULL) && (M(obj)->type != MATCHER_ISNNULL))
577 return -1;
579 ISNULL_M(obj)->expr = va_arg(ap, sdb_store_expr_t *);
580 sdb_object_ref(SDB_OBJ(ISNULL_M(obj)->expr));
581 return 0;
582 } /* isnull_matcher_init */
584 static void
585 isnull_matcher_destroy(sdb_object_t *obj)
586 {
587 sdb_object_deref(SDB_OBJ(ISNULL_M(obj)->expr));
588 ISNULL_M(obj)->expr = NULL;
589 } /* isnull_matcher_destroy */
591 static sdb_type_t name_type = {
592 /* size = */ sizeof(name_matcher_t),
593 /* init = */ name_matcher_init,
594 /* destroy = */ name_matcher_destroy,
595 };
597 static sdb_type_t op_type = {
598 /* size = */ sizeof(op_matcher_t),
599 /* init = */ op_matcher_init,
600 /* destroy = */ op_matcher_destroy,
601 };
603 static sdb_type_t uop_type = {
604 /* size = */ sizeof(uop_matcher_t),
605 /* init = */ uop_matcher_init,
606 /* destroy = */ uop_matcher_destroy,
607 };
609 static sdb_type_t child_type = {
610 /* size = */ sizeof(child_matcher_t),
611 /* init = */ child_matcher_init,
612 /* destroy = */ child_matcher_destroy,
613 };
615 static sdb_type_t cmp_type = {
616 /* size = */ sizeof(cmp_matcher_t),
617 /* init = */ cmp_matcher_init,
618 /* destroy = */ cmp_matcher_destroy,
619 };
621 static sdb_type_t isnull_type = {
622 /* size = */ sizeof(isnull_matcher_t),
623 /* init = */ isnull_matcher_init,
624 /* destroy = */ isnull_matcher_destroy,
625 };
627 /*
628 * public API
629 */
631 sdb_store_matcher_t *
632 sdb_store_name_matcher(int type, const char *name, _Bool re)
633 {
634 sdb_store_matcher_t *m;
636 if (re)
637 m = M(sdb_object_create("name-matcher", name_type, NULL, name));
638 else
639 m = M(sdb_object_create("name-matcher", name_type, name, NULL));
641 if (! m)
642 return NULL;
644 NAME_M(m)->obj_type = type;
645 return m;
646 } /* sdb_store_name_matcher */
648 sdb_store_matcher_t *
649 sdb_store_child_matcher(int type, sdb_store_matcher_t *m)
650 {
651 if (type == SDB_SERVICE)
652 type = MATCHER_SERVICE;
653 else if (type == SDB_METRIC)
654 type = MATCHER_METRIC;
655 else if (type == SDB_ATTRIBUTE)
656 type = MATCHER_ATTRIBUTE;
657 else
658 return NULL;
659 return M(sdb_object_create("any-matcher", child_type, type, m));
660 } /* sdb_store_child_matcher */
662 sdb_store_matcher_t *
663 sdb_store_lt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
664 {
665 return M(sdb_object_create("lt-matcher", cmp_type,
666 MATCHER_LT, left, right));
667 } /* sdb_store_lt_matcher */
669 sdb_store_matcher_t *
670 sdb_store_le_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
671 {
672 return M(sdb_object_create("le-matcher", cmp_type,
673 MATCHER_LE, left, right));
674 } /* sdb_store_le_matcher */
676 sdb_store_matcher_t *
677 sdb_store_eq_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
678 {
679 return M(sdb_object_create("eq-matcher", cmp_type,
680 MATCHER_EQ, left, right));
681 } /* sdb_store_eq_matcher */
683 sdb_store_matcher_t *
684 sdb_store_ne_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
685 {
686 return M(sdb_object_create("ne-matcher", cmp_type,
687 MATCHER_NE, left, right));
688 } /* sdb_store_ne_matcher */
690 sdb_store_matcher_t *
691 sdb_store_ge_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
692 {
693 return M(sdb_object_create("ge-matcher", cmp_type,
694 MATCHER_GE, left, right));
695 } /* sdb_store_ge_matcher */
697 sdb_store_matcher_t *
698 sdb_store_gt_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
699 {
700 return M(sdb_object_create("gt-matcher", cmp_type,
701 MATCHER_GT, left, right));
702 } /* sdb_store_gt_matcher */
704 sdb_store_matcher_t *
705 sdb_store_in_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
706 {
707 return M(sdb_object_create("in-matcher", cmp_type,
708 MATCHER_IN, left, right));
709 } /* sdb_store_in_matcher */
711 sdb_store_matcher_t *
712 sdb_store_regex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
713 {
714 if (! right->type) {
715 if ((right->data.type != SDB_TYPE_STRING)
716 && (right->data.type != SDB_TYPE_REGEX))
717 return NULL;
719 if (right->data.type == SDB_TYPE_STRING) {
720 char *raw = right->data.data.string;
721 if (sdb_data_parse(raw, SDB_TYPE_REGEX, &right->data))
722 return NULL;
723 free(raw);
724 }
725 }
726 return M(sdb_object_create("regex-matcher", cmp_type,
727 MATCHER_REGEX, left, right));
728 } /* sdb_store_regex_matcher */
730 sdb_store_matcher_t *
731 sdb_store_nregex_matcher(sdb_store_expr_t *left, sdb_store_expr_t *right)
732 {
733 sdb_store_matcher_t *m = sdb_store_regex_matcher(left, right);
734 if (! m)
735 return NULL;
736 m->type = MATCHER_NREGEX;
737 return m;
738 } /* sdb_store_nregex_matcher */
740 sdb_store_matcher_t *
741 sdb_store_isnull_matcher(sdb_store_expr_t *expr)
742 {
743 return M(sdb_object_create("isnull-matcher", isnull_type,
744 MATCHER_ISNULL, expr));
745 } /* sdb_store_isnull_matcher */
747 sdb_store_matcher_t *
748 sdb_store_isnnull_matcher(sdb_store_expr_t *expr)
749 {
750 return M(sdb_object_create("isnull-matcher", isnull_type,
751 MATCHER_ISNNULL, expr));
752 } /* sdb_store_isnnull_matcher */
754 sdb_store_matcher_op_cb
755 sdb_store_parse_matcher_op(const char *op)
756 {
757 if (! strcasecmp(op, "<"))
758 return sdb_store_lt_matcher;
759 else if (! strcasecmp(op, "<="))
760 return sdb_store_le_matcher;
761 else if (! strcasecmp(op, "="))
762 return sdb_store_eq_matcher;
763 else if (! strcasecmp(op, "!="))
764 return sdb_store_ne_matcher;
765 else if (! strcasecmp(op, ">="))
766 return sdb_store_ge_matcher;
767 else if (! strcasecmp(op, ">"))
768 return sdb_store_gt_matcher;
769 else if (! strcasecmp(op, "=~"))
770 return sdb_store_regex_matcher;
771 else if (! strcasecmp(op, "!~"))
772 return sdb_store_nregex_matcher;
773 return NULL;
774 } /* sdb_store_parse_matcher_op */
776 int
777 sdb_store_parse_object_type_plural(const char *name)
778 {
779 if (! strcasecmp(name, "hosts"))
780 return SDB_HOST;
781 else if (! strcasecmp(name, "services"))
782 return SDB_SERVICE;
783 else if (! strcasecmp(name, "metrics"))
784 return SDB_METRIC;
785 return -1;
786 } /* sdb_store_parse_object_type_plural */
788 int
789 sdb_store_parse_field_name(const char *name)
790 {
791 if (! strcasecmp(name, "name"))
792 return SDB_FIELD_NAME;
793 else if (! strcasecmp(name, "last_update"))
794 return SDB_FIELD_LAST_UPDATE;
795 else if (! strcasecmp(name, "age"))
796 return SDB_FIELD_AGE;
797 else if (! strcasecmp(name, "interval"))
798 return SDB_FIELD_INTERVAL;
799 else if (! strcasecmp(name, "backend"))
800 return SDB_FIELD_BACKEND;
801 return -1;
802 } /* sdb_store_parse_field_name */
804 static sdb_store_matcher_t *
805 maybe_inv_matcher(sdb_store_matcher_t *m, _Bool inv)
806 {
807 sdb_store_matcher_t *tmp;
809 if ((! m) || (! inv))
810 return m;
812 tmp = sdb_store_inv_matcher(m);
813 /* pass ownership to the inverse matcher */
814 sdb_object_deref(SDB_OBJ(m));
815 return tmp;
816 } /* maybe_inv_matcher */
818 sdb_store_matcher_t *
819 sdb_store_matcher_parse_cmp(const char *obj_type,
820 const char *op, sdb_store_expr_t *expr)
821 {
822 int type = -1;
823 _Bool inv = 0;
824 _Bool re = 0;
826 sdb_data_t value = SDB_DATA_INIT;
827 sdb_store_matcher_t *m = NULL;
829 if (! strcasecmp(obj_type, "host"))
830 type = SDB_HOST;
831 else if (! strcasecmp(obj_type, "service"))
832 type = SDB_SERVICE;
833 else if (! strcasecmp(obj_type, "metric"))
834 type = SDB_METRIC;
835 else if (! strcasecmp(obj_type, "attribute"))
836 type = SDB_ATTRIBUTE;
837 else
838 return NULL;
840 /* XXX: this code sucks! */
841 if (! strcasecmp(op, "=")) {
842 /* nothing to do */
843 }
844 else if (! strcasecmp(op, "!=")) {
845 inv = 1;
846 }
847 else if (! strcasecmp(op, "=~")) {
848 re = 1;
849 }
850 else if (! strcasecmp(op, "!~")) {
851 inv = 1;
852 re = 1;
853 }
854 else
855 return NULL;
857 if (! expr)
858 return NULL;
860 if (sdb_store_expr_eval(expr, /* obj */ NULL, &value, /* filter */ NULL)
861 || (value.type != SDB_TYPE_STRING)) {
862 sdb_data_free_datum(&value);
863 return NULL;
864 }
866 m = sdb_store_name_matcher(type, value.data.string, re);
867 sdb_data_free_datum(&value);
868 return maybe_inv_matcher(m, inv);
869 } /* sdb_store_matcher_parse_cmp */
871 sdb_store_matcher_t *
872 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
873 {
874 return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
875 left, right));
876 } /* sdb_store_dis_matcher */
878 sdb_store_matcher_t *
879 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
880 {
881 return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
882 left, right));
883 } /* sdb_store_con_matcher */
885 sdb_store_matcher_t *
886 sdb_store_inv_matcher(sdb_store_matcher_t *m)
887 {
888 return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
889 } /* sdb_store_inv_matcher */
891 int
892 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_obj_t *obj,
893 sdb_store_matcher_t *filter)
894 {
895 if (filter && (! sdb_store_matcher_matches(filter, obj, NULL)))
896 return 0;
898 /* "NULL" always matches */
899 if ((! m) || (! obj))
900 return 1;
902 if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
903 return 0;
905 return matchers[m->type](m, obj, filter);
906 } /* sdb_store_matcher_matches */
908 int
909 sdb_store_scan(sdb_store_matcher_t *m, sdb_store_matcher_t *filter,
910 sdb_store_lookup_cb cb, void *user_data)
911 {
912 scan_iter_data_t data = { m, filter, cb, user_data };
914 if (! cb)
915 return -1;
916 return sdb_store_iterate(scan_iter, &data);
917 } /* sdb_store_scan */
919 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */