3 * If you belong to the group where do you belong only in the case you belong
4 * in that group, do you in fact belong to that group or don't?
5 * I've decided it is safer to decide that you DON'T belong to such group.
7 * expr_eval_notify_expr_remove():
8 * If someone was interested in what am I like but she is no longer
9 * interested in what am I like, because she already knows what is she like,
10 * then she should tell it me, as although I still may not know what am I
11 * like then in the case she was the last who wanted to know what am I like,
12 * I should tell everyone who I didn't know what they are like and I wanted
13 * to know what they are like that I no longer want to know what they are
14 * like, because it is no longer needed to know what am I like about myself.
16 * membership_eval_immediate():
17 * It is important to not only know, what do you want to know, but it is also
18 * important to know what do you now know but you still didn't utilize it.
37 /* Whether to do sanity checks */
38 #define SCAN_PARANOIA 1
40 /* report even no-op scan up-to-date checks */
41 #define REPORT_CHECK_SCAN_VERBOSE 0
44 static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
45 static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
46 static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
47 static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
48 static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
51 static unsigned request_scan_seq = 0;
52 static unsigned value_scan_seq = 0;
53 static unsigned eval_scan_seq = 0;
54 int request_scan_user_known;
55 static struct tac_list eval_kicked_entity_list;
56 static struct tac_list eval_destroy_entity_list;
57 static struct tac_list eval_notified_expr_list;
58 static struct tac_list request_virtual_membership_list;
61 /* 'P[FA]_*' object printing section:
64 static const char *eval_result_to_string TAC_ARGS((int valid, enum eval_result er));
67 eval_result_to_string(valid, er)
75 case ER_TRUE: return ("ER_TRUE" );
76 case ER_FALSE: return ("ER_FALSE" );
77 case ER_UNKNOWN: return ("ER_UNKNOWN" );
78 default: return ("*** INVALID ***");
83 static const char *value_scan_func_result_to_string TAC_ARGS((enum value_scan_func_result vsfr));
86 value_scan_func_result_to_string(vsfr)
87 enum value_scan_func_result vsfr;
90 case VSFR_CONTINUE: return ("VSFR_CONTINUE");
91 case VSFR_FOUND: return ("VSFR_FOUND" );
92 case VSFR_STOP: return ("VSFR_STOP" );
93 default: return ("*** INVALID ***");
98 /* These macros are VERY big overhead but it's primary negative effect
99 * is the size of executable. I've considered it as not much interesting,
100 * CPU overhead is hit only when DEBUG_CFGEVAL_FLAG (also not interesting).
104 #define PA_VSFR(vsfr) (value_scan_func_result_to_string((vsfr)))
106 #define PF_RESULT "%s"
107 #define PA_RESULT(result) (eval_result_to_string(1 /* valid */, (result)))
109 #define PF_ERESULT_struct PF_RESULT
110 #define PA_ERESULT_struct(entity, field) \
111 (!(entity) ? "*NULL*(=ER_TRUE)" : \
112 (eval_result_to_string((entity)->request_scan.seq == request_scan_seq, (entity)->request_scan.field)))
113 #define PA_ERESULT_struct_NULL "*NULL*"
115 #define PF_ERESULT_EXPR PF_ERESULT_struct
116 #define PA_ERESULT_EXPR(expr) PA_ERESULT_struct((expr), result)
117 #define PF_ERESULT_ENTITY PF_ERESULT_struct
118 #define PA_ERESULT_ENTITY(entity) PA_ERESULT_struct((entity), belongs)
119 #define PF_ERESULT_MEMBERSHIP PF_ERESULT_struct
120 #define PA_ERESULT_MEMBERSHIP(membership) (!(membership) ? PA_ERESULT_struct_NULL : PA_ERESULT_EXPR((membership)->when))
122 #define PF_EXPR_ "expr@%d{%s " PF_MEMBERSHIP "}"
123 #define PA_EXPR_(expr) (!(expr) ? 0 : (expr)->line), \
124 (!(expr) ? "*NULL*" : "of"), \
125 PA_MEMBERSHIP((!(expr) ? NULL : (expr)->membership))
127 #define PF_MEMBERSHIP_ "membership{child=" PF_ENTITY ",parent=" PF_ENTITY "}"
128 #define PA_MEMBERSHIP_(membership) PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_CHILD_ENTITY( (membership)))), \
129 PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_PARENT_ENTITY((membership))))
131 #define PF_ENTITY_ "{%s@%d \"%s\"}"
132 #define PA_ENTITY_(entity) (!(entity) ? "*NULL* entity" : entity_type_to_string((entity)->type)), \
133 (!(entity) ? 0 : (entity)->line), \
134 (!(entity) ? "*NULL*" : (entity)->name)
136 #define PF_EXPR PF_EXPR_ "=" PF_ERESULT_EXPR
137 #define PA_EXPR(expr) PA_EXPR_(expr), PA_ERESULT_EXPR(expr)
138 #define PF_MEMBERSHIP PF_MEMBERSHIP_ "=" PF_ERESULT_MEMBERSHIP
139 #define PA_MEMBERSHIP(membership) PA_MEMBERSHIP_(membership), PA_ERESULT_MEMBERSHIP(membership)
140 #define PF_ENTITY PF_ENTITY_ "=" PF_ERESULT_ENTITY
141 #define PA_ENTITY(entity) PA_ENTITY_(entity), PA_ERESULT_ENTITY(entity)
144 /* '{unlink,free}_*()' section:
147 void unlink_expr TAC_ARGS((struct expr *expr));
149 /* never depend on "->parent" as it may not yet been filled! */
155 return; /* prevent possible DEBUG_CLEAN_FLAG report */
157 if (debug & DEBUG_CLEAN_FLAG) {
158 if (expr->membership)
159 report(LOG_DEBUG, "unlink_expr: (of membership): " PF_EXPR,
162 report(LOG_DEBUG, "unlink_expr: (standalone)");
167 /* We need to at least unlink "eval_scan->u.entity.notify_expr_node": */
168 check_request_scan_expr(expr, 1); /* invalidate */
169 check_eval_scan_expr(expr, 1); /* invalidate */
171 switch (expr->type) {
174 unlink_expr(expr->u.not.child);
179 unlink_expr(expr->u.and_or.child_first);
188 report(LOG_ERR, "Illegal node type %d for unlink_expr", expr->type);
196 void free_expr TAC_ARGS((struct expr *expr));
198 /* given 'expr' memory WILL be freed! */
199 /* never depend on "->parent" as it may not yet been filled! */
204 struct expr *expr_next;
207 return; /* prevent possible DEBUG_CLEAN_FLAG report */
209 if (debug & DEBUG_CLEAN_FLAG)
210 report(LOG_DEBUG, "free_expr: (may be unlinked)");
213 expr_next = expr->next;
214 switch (expr->type) {
217 free_expr(expr->u.not.child);
222 free_expr(expr->u.and_or.child_first);
228 if (expr->u.entity.name)
229 free((/* de-const */ char *)expr->u.entity.name);
230 /* "expr->u.entity.entity" will be freed from elsewhere */
234 report(LOG_ERR, "Illegal node type %d for free_expr", expr->type);
243 static void unlink_membership TAC_ARGS((struct membership *membership));
246 unlink_membership(membership)
247 struct membership *membership;
249 ENTITY *parent_entity;
251 if (debug & DEBUG_CFGEVAL_FLAG)
252 report(LOG_DEBUG, "unlink_membership: " PF_MEMBERSHIP,
253 PA_MEMBERSHIP(membership));
255 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
257 /* 'unlink_expr()' may want a lot of existing (linked) resources */
258 unlink_expr(membership->when);
260 check_request_scan_membership(membership, 1); /* invalidate */
261 check_eval_scan_membership(membership, 1); /* invalidate */
264 if (!parent_entity->to_child_membership_num) {
265 report(LOG_ERR, "INTERNAL: to_child_membership_num-- == 0 in unlink_membership");
266 parent_entity->to_child_membership_num++;
269 parent_entity->to_child_membership_num--;
271 tac_list_node_remove(&membership->parent_node);
272 tac_list_node_remove(&membership-> child_node);
275 /* given 'membership' memory WILL be freed! */
277 static void free_membership TAC_ARGS((struct membership *membership));
280 free_membership(membership)
281 struct membership *membership;
283 if (debug & DEBUG_CLEAN_FLAG)
284 report(LOG_DEBUG, "free_membership: (may be unlinked)");
286 free_expr(membership->when);
290 /* we are not allowed to free memory here, we are only 'scan_' additional 'free' */
292 void scan_free_entity TAC_ARGS((ENTITY *entity));
295 scan_free_entity(entity)
298 struct tac_list_node *parent_membership_node, *next_parent_membership_node;
299 struct membership *parent_membership;
300 struct tac_list_node *child_membership_node, *next_child_membership_node;
301 struct membership *child_membership;
303 if (debug & DEBUG_CLEAN_FLAG)
304 report(LOG_DEBUG, "scan_free_entity: " PF_ENTITY,
307 /* Be careful to keep '->next' ptr before we destroy the structure! */
310 parent_membership_node = tac_list_first_node(&entity->to_child_membership_list);
311 parent_membership_node;
312 parent_membership_node = next_parent_membership_node
314 parent_membership = PARENT_NODE_TO_MEMBERSHIP(parent_membership_node);
315 next_parent_membership_node = tac_list_node_next(parent_membership_node);
316 unlink_membership(parent_membership);
317 free_membership(parent_membership);
320 child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
321 child_membership_node;
322 child_membership_node = next_child_membership_node
324 child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
325 next_child_membership_node = tac_list_node_next(child_membership_node);
326 unlink_membership(child_membership);
327 free_membership(child_membership);
331 struct expr *new_expr TAC_ARGS((int type));
339 expr = (struct expr *) tac_malloc(sizeof(struct expr));
342 switch (expr->type) {
345 expr->u.not.child = NULL;
350 expr->u.and_or.child_first = NULL;
356 expr->u.entity.entity = NULL;
360 report(LOG_ERR, "Illegal node type %d for new_expr", expr->type);
361 return (expr); /* it would be probably lethal to return NULL */
366 static int expr_sink_internal TAC_ARGS((struct expr *expr, struct membership *membership, struct expr *parent));
369 expr_sink_internal(expr, membership, parent)
371 struct membership *membership;
374 for (;expr; expr=expr->next) {
375 expr->membership = membership;
376 expr->parent = parent;
377 expr->request_scan.seq = request_scan_seq-1;
378 expr-> eval_scan.seq = eval_scan_seq-1;
379 switch (expr->type) {
382 if (expr_sink_internal(expr->u.not.child, membership, expr /* parent */))
388 if (expr_sink_internal(expr->u.and_or.child_first, membership, expr /* parent */))
395 tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
396 expr->u.entity.entity = entity_lookup(expr->type, expr->u.entity.name);
397 if (!expr->u.entity.entity && expr->type == S_host) {
398 expr->u.entity.entity = new_entity(expr->type, (char *)expr->u.entity.name, expr->line);
399 if (!expr->u.entity.entity)
401 expr->u.entity.name = NULL;
403 if (!expr->u.entity.entity) {
404 report(LOG_ERR, "referenced entity %s %s not found on line %d",
405 entity_type_to_string(expr->type), expr->u.entity.name, expr->line);
408 /* already NULLed for not-yet-existing S_host */
409 free((char *) expr->u.entity.name);
410 expr->u.entity.name = NULL;
414 report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
421 static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
424 expr_sink(expr, membership)
426 struct membership *membership;
428 return (expr_sink_internal(expr, membership, NULL /* parent */));
431 static struct expr *expr_sink_register_head = NULL;
433 void expr_sink_register TAC_ARGS((struct expr *expr));
436 expr_sink_register(expr)
442 expr->parent = expr_sink_register_head;
443 expr_sink_register_head = expr;
446 int expr_sink_commit TAC_ARGS((void));
453 while ((expr = expr_sink_register_head)) {
454 expr_sink_register_head = expr->parent;
455 /* 'expr->parent' not defined for 'expr_sink()' */
457 if (expr_sink(expr, NULL /* membership */))
458 return (1); /* failure */
460 return (0); /* success */
463 struct expr *dupl_expr TAC_ARGS((const struct expr *in));
467 const struct expr *in;
469 struct expr *expr_root = NULL;
470 struct expr **succ_exprp = &expr_root;
473 for (;in; in=in->next) {
474 expr = (struct expr *) tac_malloc(sizeof(struct expr));
475 expr->line = in->line;
477 expr->type = in->type;
481 if (in->u.not.child && in->u.not.child->type==S_not) {
483 expr = dupl_expr(in->u.not.child->u.not.child);
485 expr->u.not.child = dupl_expr(in->u.not.child);
490 if (!in->u.and_or.child_first) {
493 } else if (!in->u.and_or.child_first->next) {
495 expr = dupl_expr(in->u.and_or.child_first);
497 expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
503 if (in->u.entity.name)
504 expr->u.entity.name = tac_strdup(in->u.entity.name);
506 expr->u.entity.name = NULL;
507 expr->u.entity.entity = in->u.entity.entity;
511 report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
512 free_expr(expr_root);
517 succ_exprp = &expr->next;
523 /* 'check_*_scan_*()' section:
526 static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
529 check_request_scan_expr(expr, flush)
533 #if REPORT_CHECK_SCAN_VERBOSE
534 if (debug & DEBUG_CFGEVAL_FLAG)
535 report(LOG_DEBUG, "check_request_scan_expr: " PF_EXPR " (" PF_ERESULT_EXPR ")",
536 PA_EXPR(expr), PA_ERESULT_EXPR(expr));
539 if (!flush && expr->request_scan.seq == request_scan_seq)
540 return; /* up to date */
542 expr->request_scan.result = ER_UNKNOWN;
543 expr->request_scan.loop_reported = 0;
544 expr->request_scan.seq = request_scan_seq;
546 if (debug & DEBUG_CFGEVAL_FLAG)
547 report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
551 static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
554 check_eval_scan_expr(expr, flush)
558 #if REPORT_CHECK_SCAN_VERBOSE
559 if (debug & DEBUG_CFGEVAL_FLAG)
560 report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
564 if (!flush && expr->eval_scan.seq == eval_scan_seq)
565 return; /* up to date */
566 check_request_scan_expr(expr, 0);
568 switch (expr->type) {
574 if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node) == &eval_notified_expr_list) {
575 report(LOG_ERR, "INTERNAL: expr still connected to eval_notified_expr_list in check_eval_scan_expr");
576 } else if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
577 ENTITY *notifying_entity = EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr);
579 if (notifying_entity != expr->u.entity.entity)
580 report(LOG_ERR, "INTERNAL: expr->notify_expr_node->list != expr->entity");
581 if (notifying_entity->eval_scan.seq != expr->eval_scan.seq)
582 report(LOG_ERR, "INTERNAL: entity seq != expr node seq");
583 tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
585 #else /* SCAN_PARANOIA */
586 tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
587 #endif /* SCAN_PARANOIA */
591 expr->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
593 if (debug & DEBUG_CFGEVAL_FLAG)
594 report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
598 static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
601 check_request_scan_membership(membership, flush)
602 struct membership *membership;
605 #if REPORT_CHECK_SCAN_VERBOSE
606 if (debug & DEBUG_CFGEVAL_FLAG)
607 report(LOG_DEBUG, "check_request_scan_membership: " PF_MEMBERSHIP " (" PF_ERESULT_MEMBERSHIP ")",
608 PA_MEMBERSHIP(membership), PA_ERESULT_MEMBERSHIP(membership));
611 if (!flush && membership->request_scan.seq == request_scan_seq)
612 return; /* up to date */
616 struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
618 if (virtual_list && virtual_list != &request_virtual_membership_list)
619 report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
621 tac_list_node_remove(&membership->request_scan.virtual_membership_node);
623 #else /* SCAN_PARANOIA */
624 tac_list_node_init(&membership->request_scan.virtual_membership_node);
625 #endif /* SCAN_PARANOIA */
627 membership->request_scan.seq = request_scan_seq; /* used above, keep as LAST! */
629 if (debug & DEBUG_CFGEVAL_FLAG)
630 report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
631 PA_MEMBERSHIP(membership));
634 /* we are cross-checking (membership<->parent entity)! */
636 static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
639 check_eval_scan_membership(membership, flush)
640 struct membership *membership;
643 #if REPORT_CHECK_SCAN_VERBOSE
644 if (debug & DEBUG_CFGEVAL_FLAG)
645 report(LOG_DEBUG, "check_eval_scan_membership: " PF_MEMBERSHIP,
646 PA_MEMBERSHIP(membership));
649 if (!flush && membership->eval_scan.seq == eval_scan_seq)
650 return; /* up to date */
651 check_request_scan_membership(membership, 0);
653 membership->eval_scan.unsolved = 1;
654 membership->eval_scan.seq = eval_scan_seq;
656 if (debug & DEBUG_CFGEVAL_FLAG)
657 report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
658 PA_MEMBERSHIP(membership));
661 static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
664 check_request_scan_entity(entity, flush)
668 #if REPORT_CHECK_SCAN_VERBOSE
669 if (debug & DEBUG_CFGEVAL_FLAG)
670 report(LOG_DEBUG, "check_request_scan_entity: " PF_ENTITY " (" PF_ERESULT_ENTITY ")",
671 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
674 if (!flush && entity->request_scan.seq == request_scan_seq)
677 entity->request_scan.belongs = ER_UNKNOWN;
678 entity->request_scan.seq = request_scan_seq;
680 if (debug & DEBUG_CFGEVAL_FLAG)
681 report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
685 static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
688 check_value_scan_entity(entity, flush)
692 #if REPORT_CHECK_SCAN_VERBOSE
693 if (debug & DEBUG_CFGEVAL_FLAG)
694 report(LOG_DEBUG, "check_value_scan_entity: " PF_ENTITY,
698 if (!flush && entity->value_scan.seq == value_scan_seq)
700 check_request_scan_entity(entity, 0);
702 entity->value_scan.seen = 0;
703 entity->value_scan.from = NULL;
704 entity->value_scan.seq = value_scan_seq;
706 if (debug & DEBUG_CFGEVAL_FLAG)
707 report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
711 static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
714 check_eval_scan_entity(entity, flush)
718 struct tac_list_node *child_membership_parent_node;
720 #if REPORT_CHECK_SCAN_VERBOSE
721 if (debug & DEBUG_CFGEVAL_FLAG)
722 report(LOG_DEBUG, "check_eval_scan_entity: " PF_ENTITY,
726 if (!flush && entity->eval_scan.seq == eval_scan_seq)
727 return; /* up to date */
728 check_value_scan_entity(entity, 0);
730 entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
732 if ((child_membership_parent_node = tac_list_first_node(&entity->to_child_membership_list))) {
733 struct membership *child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_parent_node);
735 entity->eval_scan.unsolved_to_child_membership_first = child_membership;
737 entity->eval_scan.unsolved_to_child_membership_first = NULL;
741 struct tac_list_node *notify_expr_node;
743 while ((notify_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
744 struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
746 if (notify_expr->u.entity.entity != entity)
747 report(LOG_ERR, "INTERNAL: notify_expr->entity != entity");
748 if (notify_expr->eval_scan.seq != entity->eval_scan.seq)
749 report(LOG_ERR, "INTERNAL: notify_expr seq != entity seq");
750 tac_list_node_remove(notify_expr_node);
753 if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
754 tac_list_node_remove(&entity->eval_scan.pending_entity_node);
756 #else /* SCAN_PARANOIA */
757 tac_list_init(&entity->eval_scan.notify_expr_list);
758 tac_list_node_init(&entity->eval_scan.pending_entity_node);
759 #endif /* SCAN_PARANOIA */
761 entity->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
763 if (debug & DEBUG_CFGEVAL_FLAG)
764 report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
769 /* invalidation managing section (for '*_scan_begin()'):
772 /* this will happen once upon 'unsigned' overflow, ehm */
774 #define INVALIDATE_SEQ_PTR(object,ptr) \
775 (G_STRUCT_MEMBER(unsigned, ptr, invalidate_scan_##object##_table[what]) = (unsigned) -1)
776 #define INVALIDATE_SEQ(object) \
777 (INVALIDATE_SEQ_PTR(object,object))
779 static const long invalidate_scan_expr_table[IS_MAX]={
780 G_STRUCT_OFFSET(struct expr, request_scan.seq),
782 G_STRUCT_OFFSET(struct expr, eval_scan.seq)};
784 static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
787 invalidate_scan_expr(expr_single, what)
788 struct expr *expr_single;
789 enum invalidate_scan what;
791 struct expr *expr_parent, *expr_child;
794 report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
797 if (expr_single->parent) {
798 report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
802 /* TOP->DOWN scanner: */
805 INVALIDATE_SEQ_PTR(expr,expr_single);
806 expr_parent = expr_single;
808 switch (expr_parent->type) {
811 expr_child = expr_parent->u.not.child;
816 expr_child = expr_parent->u.and_or.child_first;
822 expr_child = NULL; /* no child exists */
826 report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
829 } while ((expr_single = expr_child));
830 /* expr_child==NULL, we have only expr_parent: */
832 expr_child = expr_parent;
834 /* we have only expr_child: */
835 /* BOTTOM->UP scanner */
837 if ((expr_single = expr_child->next))
839 expr_parent = expr_child->parent;
840 } while ((expr_child = expr_parent));
843 static const long invalidate_scan_membership_table[IS_MAX]={
844 G_STRUCT_OFFSET(struct membership, request_scan.seq),
846 G_STRUCT_OFFSET(struct membership, eval_scan.seq)};
848 static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
851 invalidate_scan_membership(membership, what)
852 struct membership *membership;
853 enum invalidate_scan what;
855 INVALIDATE_SEQ(membership);
857 if (membership->when)
858 invalidate_scan_expr(membership->when, what);
861 static const long invalidate_scan_entity_table[IS_MAX]={
862 G_STRUCT_OFFSET(ENTITY, request_scan.seq),
863 G_STRUCT_OFFSET(ENTITY, value_scan.seq),
864 G_STRUCT_OFFSET(ENTITY, eval_scan.seq)};
866 static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
869 invalidate_scan_entity(entity, what)
871 enum invalidate_scan what;
873 struct tac_list_node *child_membership_node;
874 struct membership *child_membership;
876 INVALIDATE_SEQ(entity);
878 if (what==IS_VALUE) /* optimalization */
882 child_membership_node = tac_list_first_node(&entity->to_child_membership_list);
883 child_membership_node;
884 child_membership_node = tac_list_node_next(&child_membership->parent_node)
886 child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
887 invalidate_scan_membership(child_membership, what);
891 void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
894 scan_invalidate_entities_hashtable(hashtable, what)
896 enum invalidate_scan what;
901 for (i = 0; i < HASH_TAB_SIZE; i++)
902 for (entity = (ENTITY *) hashtable[i]; entity; entity = entity->hash)
903 invalidate_scan_entity(entity, what);
906 /* '*_scan_begin()' section:
909 void request_scan_begin TAC_ARGS((void));
915 static int inited = 0;
916 #endif /* SCAN_PARANOIA */
918 if (debug & DEBUG_CFGEVAL_FLAG)
919 report(LOG_DEBUG, "request_scan_begin:");
921 request_scan_user_known = 0;
923 if (!++request_scan_seq)
924 scan_invalidate_entities(IS_REQUEST);
928 #endif /* SCAN_PARANOIA */
929 tac_list_init(&request_virtual_membership_list);
933 struct tac_list_node *virtual_membership_node;
935 while ((virtual_membership_node = tac_list_first_node(&request_virtual_membership_list))) {
936 struct membership *virtual_membership = VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node);
938 if (virtual_membership->request_scan.seq == request_scan_seq)
939 report(LOG_ERR, "INTERNAL: request_virtual_membership_list membership seq == ++request_scan_seq in request_scan_begin");
940 tac_list_node_remove(virtual_membership_node);
941 unlink_membership(virtual_membership);
942 free_membership(virtual_membership);
945 #endif /* SCAN_PARANOIA */
948 static void value_scan_begin TAC_ARGS((ENTITY *entity));
951 value_scan_begin(entity)
954 if (debug & DEBUG_CFGEVAL_FLAG)
955 report(LOG_DEBUG, "value_scan_begin:");
957 if (!++value_scan_seq)
958 scan_invalidate_entities(IS_VALUE);
960 check_value_scan_entity(entity, 0); /* sure as seq invalidated */
961 /* assumed (entity->value_scan.from == NULL) */
966 static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
969 eval_scan_begin_pending_entity_node(pending_entity_node)
970 struct tac_list_node *pending_entity_node;
972 ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
974 if (pending_entity->eval_scan.seq == eval_scan_seq)
975 report(LOG_ERR, "INTERNAL: eval_{pending}_entity_list entity seq == ++eval_scan_seq in eval_scan_begin");
977 tac_list_node_remove(pending_entity_node);
980 #endif /* SCAN_PARANOIA */
982 static void eval_scan_begin TAC_ARGS((void));
988 static int inited = 0;
989 #endif /* SCAN_PARANOIA */
991 if (debug & DEBUG_CFGEVAL_FLAG)
992 report(LOG_DEBUG, "eval_scan_begin:");
994 if (!++eval_scan_seq)
995 scan_invalidate_entities(IS_EVAL);
999 #endif /* SCAN_PARANOIA */
1000 tac_list_init(&eval_kicked_entity_list);
1001 tac_list_init(&eval_destroy_entity_list);
1002 tac_list_init(&eval_notified_expr_list);
1003 #ifdef SCAN_PARANOIA
1006 struct tac_list_node *pending_entity_node;
1007 struct tac_list_node *notify_expr_node;
1009 while ((pending_entity_node = tac_list_first_node(&eval_kicked_entity_list)))
1010 eval_scan_begin_pending_entity_node(pending_entity_node);
1011 while ((pending_entity_node = tac_list_first_node(&eval_destroy_entity_list)))
1012 eval_scan_begin_pending_entity_node(pending_entity_node);
1014 while ((notify_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1015 struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
1017 if (notify_expr->eval_scan.seq == eval_scan_seq)
1018 report(LOG_ERR, "INTERNAL: eval_notified_expr_list expr seq == ++eval_scan_seq in eval_scan_begin");
1020 tac_list_node_remove(notify_expr_node);
1023 #endif /* SCAN_PARANOIA */
1026 /* 'priority=0' => addtail - used for WANTED entities
1027 * 'priority=1' => addhead - used for SOLVED entities
1028 * It may be better to do insert it AFTER all currently solved
1029 * entities but may be not but who cares...
1032 static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
1034 static void register_kicked_entity(entity, priority)
1038 struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1040 check_eval_scan_entity(entity, 0);
1042 if (tac_list_node_get_list(pending_entity_node) == &eval_destroy_entity_list) {
1043 tac_list_node_remove (pending_entity_node);
1044 if (debug & DEBUG_CFGEVAL_FLAG)
1045 report(LOG_DEBUG, "register_kicked_entity: REMOVED " PF_ENTITY " from eval_DESTROY_entity_list",
1048 if (tac_list_node_get_list(pending_entity_node) == NULL) {
1050 tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
1052 tac_list_addtail(&eval_kicked_entity_list, pending_entity_node);
1053 if (debug & DEBUG_CFGEVAL_FLAG)
1054 report(LOG_DEBUG, "register_kicked_entity: REGISTERED " PF_ENTITY " to eval_KICKED_entity_list (priority=%s)",
1055 PA_ENTITY(entity), (priority ? "YES" : "NO"));
1057 #ifdef SCAN_PARANOIA
1058 if ((tac_list_node_get_list(pending_entity_node) != &eval_kicked_entity_list)) {
1059 report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1065 /* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
1067 static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
1070 expr_eval_notify_expr(expr)
1073 ENTITY *entity = expr->u.entity.entity;
1075 if (debug & DEBUG_CFGEVAL_FLAG)
1076 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED notify " PF_EXPR " when " PF_ENTITY " is known",
1077 PA_EXPR(expr), PA_ENTITY(entity));
1079 if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
1080 #ifdef SCAN_PARANOIA
1081 if (&entity->eval_scan.notify_expr_list
1082 != tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1083 report(LOG_ERR, "Another " PF_ENTITY " already registered in notify node of " PF_EXPR,
1084 PA_ENTITY(EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr)), PA_EXPR(expr));
1089 tac_list_addtail(&entity->eval_scan.notify_expr_list,
1090 &expr->eval_scan.u.entity.notify_expr_node);
1092 register_kicked_entity(entity, 0 /* priority */);
1095 /* check_eval_scan_*() is assumed for "expr" ! */
1097 static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
1100 expr_eval_notify_expr_remove_internal(expr)
1103 if (debug & DEBUG_CFGEVAL_FLAG)
1104 report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
1109 if (expr->eval_scan.seq != eval_scan_seq)
1111 if (expr->request_scan.result != ER_UNKNOWN)
1114 switch (expr->type) {
1117 expr_eval_notify_expr_remove_internal(expr->u.not.child);
1124 for (child=expr->u.and_or.child_first; child; child=child->next)
1125 expr_eval_notify_expr_remove_internal(child);
1131 ENTITY *entity = expr->u.entity.entity;
1132 struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1134 if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1137 tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
1138 if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
1140 /* no one is further interested in "entity" */
1142 if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
1143 tac_list_node_remove (pending_entity_node);
1144 if (debug & DEBUG_CFGEVAL_FLAG)
1145 report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
1148 if (tac_list_node_get_list(pending_entity_node) == NULL) {
1149 tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
1150 if (debug & DEBUG_CFGEVAL_FLAG)
1151 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
1154 #ifdef SCAN_PARANOIA
1155 if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
1156 report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1164 report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
1169 static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
1171 static void expr_eval_notify_expr_flush_destroy_entity_list()
1173 struct tac_list_node *destroy_entity_node;
1175 while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
1176 ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
1177 struct tac_list_node *destroy_notify_expr_node;
1179 if (debug & DEBUG_CFGEVAL_FLAG)
1180 report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
1181 PA_ENTITY(destroy_entity));
1183 while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
1184 struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
1186 expr_eval_notify_expr_remove_internal(destroy_notify_expr);
1191 static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
1194 expr_eval_notify_expr_remove(expr)
1197 if (debug & DEBUG_CFGEVAL_FLAG)
1198 report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
1201 expr_eval_notify_expr_remove_internal(expr);
1202 expr_eval_notify_expr_flush_destroy_entity_list();
1205 /* It would be very nice to try to optimize the expression before evaluation.
1207 We are not interested in some CPU time complexity of the expression.
1208 But we would be very happy to discard any user/host/group membership
1209 dependencies (our 'variables'). Unfortunately such optimization is
1210 NP problem (classification by courtesy of Daniel Kral) so it is considered
1211 too expensive for us.
1213 TODO in future: Full NP optimization for small number of variables and/or
1214 heuristic optimizations for complex expressions.
1217 static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
1219 static enum eval_result
1220 expr_eval_immediate(expr_single)
1221 struct expr *expr_single;
1223 struct expr *expr_child, *expr_parent;
1224 enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
1226 if (debug & DEBUG_CFGEVAL_FLAG)
1227 report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
1228 PA_EXPR(expr_single));
1233 /* TOP->DOWN scanner: */
1236 enum eval_result result_single;
1238 if (debug & DEBUG_CFGEVAL_FLAG)
1239 report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
1240 PA_EXPR(expr_single));
1242 check_eval_scan_expr(expr_single, 0);
1243 result_single = expr_single->request_scan.result;
1244 if (result_single != ER_UNKNOWN)
1246 switch (expr_single->type) {
1249 expr_single = expr_single->u.not.child;
1254 expr_single = expr_single->u.and_or.child_first;
1260 ENTITY *entity = expr_single->u.entity.entity;
1262 check_eval_scan_entity(entity, 0);
1264 if (entity->request_scan.belongs == ER_UNKNOWN)
1265 expr_eval_notify_expr(expr_single);
1267 result_single = entity->request_scan.belongs;
1271 report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
1272 return (ER_UNKNOWN);
1275 expr_single->request_scan.result = result_single;
1279 /* BOTTOM->UP scanner: */
1281 if (debug & DEBUG_CFGEVAL_FLAG)
1282 report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
1283 PA_EXPR(expr_single));
1285 expr_parent = expr_single->parent;
1288 if (expr_parent->eval_scan.seq != eval_scan_seq) {
1289 report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
1290 return (ER_UNKNOWN);
1292 if (expr_parent->request_scan.seq != request_scan_seq) {
1293 report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
1294 return (ER_UNKNOWN);
1296 if (expr_parent->request_scan.result != ER_UNKNOWN) {
1297 report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
1298 return (ER_UNKNOWN);
1301 expr_child = expr_single;
1302 result_child = expr_child->request_scan.result;
1304 if (debug & DEBUG_CFGEVAL_FLAG)
1305 report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
1306 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1308 switch (expr_parent->type) {
1311 switch (result_child) {
1312 case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
1313 case ER_FALSE: result_parent = ER_TRUE; break;
1314 case ER_TRUE: result_parent = ER_FALSE; break;
1320 enum eval_result veto = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
1321 enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE : ER_FALSE);
1323 if (result_child == veto)
1324 result_parent = veto;
1325 else if (result_child == ER_UNKNOWN || result_child == consent) {
1326 if (expr_child->next) {
1327 expr_single = expr_child->next;
1328 if (debug & DEBUG_CFGEVAL_FLAG)
1329 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
1330 PA_EXPR(expr_single));
1334 if (debug & DEBUG_CFGEVAL_FLAG)
1335 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
1336 PA_EXPR(expr_single));
1338 /* It would be nice to pretend that all 'veto' decisions already made in the child
1339 * had to set our 'result' to the correct value. But 'consent' decisions don't set
1340 * us and the behaviour of auto-set from the child in 'veto' case may get changed
1341 * in the future versions.
1342 * So we rather don't depend on it.
1343 * This overhead doesn't change altgorithmic complexity anyway.
1345 result_parent = consent;
1346 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1348 check_eval_scan_expr(expr_child, 0); /* shouldn't be needed */
1349 if (expr_child->request_scan.result == ER_UNKNOWN)
1350 result_parent = ER_UNKNOWN; /* assumed (result_parent != veto) */
1351 else if (expr_child->request_scan.result == veto) {
1352 result_parent = veto;
1361 report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1362 return (ER_UNKNOWN);
1365 if (debug & DEBUG_CFGEVAL_FLAG)
1366 report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1367 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1369 if (result_parent != ER_UNKNOWN) {
1370 expr_parent->request_scan.result = result_parent;
1371 /* we no longer need any notifications from entities to solve sub-expression */
1372 expr_eval_notify_expr_remove(expr_parent);
1375 expr_single = expr_parent;
1377 /* The whole expression has been scanned to its root, we have "expr_single" */
1379 if (debug & DEBUG_CFGEVAL_FLAG)
1380 report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1381 PA_EXPR(expr_single));
1383 return (expr_single->request_scan.result);
1386 static void membership_solved TAC_ARGS((struct membership *membership));
1389 membership_solved(membership)
1390 struct membership *membership;
1392 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1394 check_request_scan_entity(parent_entity, 0);
1396 #ifdef SCAN_PARANOIA
1397 if (!membership->eval_scan.unsolved) {
1398 report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1403 membership->eval_scan.unsolved = 0;
1405 #ifdef SCAN_PARANOIA
1406 if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1407 report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1408 parent_entity->eval_scan.unsolved_to_child_membership_num++;
1411 parent_entity->eval_scan.unsolved_to_child_membership_num--;
1413 if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1414 && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1415 parent_entity->request_scan.belongs = ER_FALSE;
1416 register_kicked_entity(parent_entity, 1 /* priority */);
1420 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1423 membership_parent_solve(membership, how)
1424 struct membership *membership;
1425 enum eval_result how;
1427 enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1428 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1430 check_request_scan_entity(parent_entity, 0);
1432 if (parent_entity->request_scan.belongs == negative)
1433 report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1434 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1436 parent_entity->request_scan.belongs = how;
1437 register_kicked_entity(parent_entity, 1 /* priority */);
1439 membership_solved(membership);
1441 if (debug & DEBUG_CFGEVAL_FLAG)
1442 report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1443 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1446 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1449 membership_eval_immediate(membership)
1450 struct membership *membership;
1452 enum eval_result membership_valid;
1453 ENTITY *child_entity, *parent_entity;
1455 if (debug & DEBUG_CFGEVAL_FLAG)
1456 report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1457 PA_MEMBERSHIP(membership));
1459 check_eval_scan_membership(membership, 0);
1461 if (!membership->eval_scan.unsolved)
1463 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1464 check_request_scan_entity(parent_entity, 0);
1465 if (parent_entity->request_scan.belongs != ER_UNKNOWN) /* why to solve this membership? */
1468 membership_valid = expr_eval_immediate(membership->when);
1470 child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1471 check_request_scan_entity( child_entity, 0);
1473 #if 0 /* non-valid membership doesn't YET solve the parent! */
1474 if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1475 membership_parent_solve(membership, ER_FALSE);
1480 if (child_entity->request_scan.belongs == ER_TRUE && membership_valid == ER_TRUE ) {
1481 membership_parent_solve(membership, ER_TRUE );
1485 if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1486 register_kicked_entity( child_entity, 0 /* priority */);
1487 if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1488 register_kicked_entity(parent_entity, 0 /* priority */);
1490 if (parent_entity->request_scan.belongs != ER_UNKNOWN
1491 || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1492 membership_solved(membership);
1494 if (debug & DEBUG_CFGEVAL_FLAG)
1495 report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1496 PA_MEMBERSHIP(membership));
1499 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1502 entity_eval_immediate(entity)
1505 struct tac_list_node *notified_expr_node;
1506 struct tac_list_node *child_membership_node;
1508 if (debug & DEBUG_CFGEVAL_FLAG)
1509 report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1512 check_eval_scan_entity(entity, 0);
1514 if (!request_scan_user_known) {
1515 #ifdef SCAN_PARANOIA
1516 if (entity->request_scan.belongs != ER_UNKNOWN)
1517 report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1523 if (entity->request_scan.belongs == ER_UNKNOWN) {
1524 if (entity->eval_scan.unsolved_to_child_membership_first) {
1525 struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1526 struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1528 membership_eval_immediate(order_membership);
1529 if (next_membership_parent_node)
1530 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1532 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1534 register_kicked_entity(entity, 0 /* priority */);
1536 if (debug & DEBUG_CFGEVAL_FLAG)
1537 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1538 PA_MEMBERSHIP(order_membership));
1542 if (!entity->eval_scan.unsolved_to_child_membership_num)
1543 entity->request_scan.belongs = ER_FALSE;
1545 if (debug & DEBUG_CFGEVAL_FLAG)
1546 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1550 /* belonging is known here */
1552 /* recheck all memberships we may decide */
1554 child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1555 child_membership_node;
1556 child_membership_node = tac_list_node_next(child_membership_node)
1558 struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1560 membership_eval_immediate(child_membership);
1563 /* notify all exprs which are interested in us */
1564 while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1565 tac_list_node_remove(notified_expr_node);
1566 tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1569 if (debug & DEBUG_CFGEVAL_FLAG)
1570 report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1575 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1581 if (debug & DEBUG_CFGEVAL_FLAG)
1582 report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1589 if (expr_eval_immediate(expr) != ER_UNKNOWN)
1590 return (expr->request_scan.result);
1592 /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1593 * otherwise we may have no longer valid node!
1596 struct tac_list_node *notified_expr_node, *kicked_entity_node;
1598 /* check it rather always, checking just on notifications looks too complex.
1600 if (expr->request_scan.result != ER_UNKNOWN) {
1601 if (debug & DEBUG_CFGEVAL_FLAG)
1602 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1604 return (expr->request_scan.result);
1607 #if 0 /* not needed as it is now always called after any destroy */
1608 expr_eval_notify_expr_flush_destroy_entity_list(); /* eval_destroy_entity_list */
1609 #endif /* not needed */
1611 if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1612 struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1614 if (debug & DEBUG_CFGEVAL_FLAG)
1615 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1616 PA_EXPR(notified_expr));
1618 tac_list_node_remove(notified_expr_node);
1619 expr_eval_immediate(notified_expr);
1621 if (notified_expr->membership)
1622 membership_eval_immediate(notified_expr->membership);
1624 continue; /* shortcut */
1627 if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1628 ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1630 if (debug & DEBUG_CFGEVAL_FLAG)
1631 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1632 PA_ENTITY(kicked_entity));
1634 tac_list_node_remove(kicked_entity_node);
1635 entity_eval_immediate(kicked_entity);
1636 continue; /* shortcut */
1639 break; /* nothing done yet, all lists are empty! */
1642 if (!expr->request_scan.loop_reported) {
1643 report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1644 expr->request_scan.loop_reported = 1;
1646 return (ER_UNKNOWN);
1650 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1652 void eval_force_belong_entity(entity)
1655 if (debug & DEBUG_CFGEVAL_FLAG)
1656 report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1657 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1659 check_request_scan_entity(entity, 0);
1661 if (entity->request_scan.belongs == ER_FALSE)
1662 report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1664 entity->request_scan.belongs = ER_TRUE;
1667 void scan_init_entity TAC_ARGS((ENTITY *entity));
1670 scan_init_entity(entity)
1673 entity->request_scan.seq = request_scan_seq-1; /* invalidate */
1674 entity-> value_scan.seq = value_scan_seq-1; /* invalidate */
1675 entity-> eval_scan.seq = eval_scan_seq-1; /* invalidate */
1676 tac_list_init(&entity->eval_scan.notify_expr_list);
1677 tac_list_node_init(&entity->eval_scan.pending_entity_node);
1680 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1683 enlist_entity_direct(parent, child, when)
1688 struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1690 tac_list_node_init(&membership->parent_node);
1691 tac_list_node_init(&membership->child_node);
1692 membership->request_scan.seq = request_scan_seq-1;
1693 tac_list_node_init(&membership->request_scan.virtual_membership_node);
1694 membership->eval_scan.seq = eval_scan_seq-1;
1696 tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1697 parent->to_child_membership_num++;
1698 tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1699 membership->when = when;
1700 if (expr_sink(membership->when, membership)) {
1701 unlink_membership(membership);
1702 free_membership(membership);
1706 if (debug & DEBUG_CFGEVAL_FLAG)
1707 report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1708 PA_MEMBERSHIP(membership));
1710 return (membership);
1713 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1716 virtual_enlist_entity_direct(parent, child)
1720 struct membership *membership;
1722 if (debug & DEBUG_CFGEVAL_FLAG)
1723 report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1725 membership = enlist_entity_direct(parent, child, NULL /* when */);
1729 check_request_scan_membership(membership, 0);
1730 tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1732 return (membership);
1735 /* returns given 'entity' or NULL if already visited */
1737 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1739 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1742 value_scan_forward(membership)
1743 struct membership *membership;
1745 ENTITY *parent_entity;
1747 if (debug & DEBUG_CFGEVAL_FLAG)
1748 report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1749 PA_MEMBERSHIP(membership));
1751 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1753 if (ER_TRUE != expr_eval(membership->when)) {
1754 if (debug & DEBUG_CFGEVAL_FLAG)
1755 report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1758 check_value_scan_entity(parent_entity, 0);
1759 if (parent_entity->value_scan.seen) {
1760 if (debug & DEBUG_CFGEVAL_FLAG)
1761 report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1762 PA_ENTITY(parent_entity));
1763 if (value_scan_forward_seen_hook)
1764 (*value_scan_forward_seen_hook)(membership);
1767 parent_entity->value_scan.seen = 1;
1768 parent_entity->value_scan.from = membership;
1770 if (debug & DEBUG_CFGEVAL_FLAG)
1771 report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1772 PA_ENTITY(parent_entity));
1773 return (parent_entity);
1776 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1779 value_scan_backward(entity)
1782 if (debug & DEBUG_CFGEVAL_FLAG)
1783 report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1784 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1786 #ifdef SCAN_PARANOIA
1787 if (entity->value_scan.seq != value_scan_seq) {
1788 report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1793 return (entity->value_scan.from);
1796 /* Scan the entity graph and return each node found.
1797 'when' conditions for graph connections are respected,
1798 looping is correctly prevented.
1801 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1803 enum value_scan_func_result
1804 value_scan_entity(entity, recurse, func, func_data)
1807 value_scan_func_t func;
1810 enum value_scan_func_result vsfr;
1811 struct tac_list_node *membership_node;
1813 if (debug & DEBUG_CFGEVAL_FLAG)
1814 report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1815 PA_ENTITY(entity), recurse);
1817 vsfr=(*func)(entity,func_data);
1819 if (debug & DEBUG_CFGEVAL_FLAG)
1820 report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1823 if (vsfr != VSFR_CONTINUE) {
1824 if (debug & DEBUG_CFGEVAL_FLAG)
1825 report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1829 if (debug & DEBUG_CFGEVAL_FLAG)
1830 report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1834 value_scan_begin(entity);
1835 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1836 if (!membership_node) {
1837 if (debug & DEBUG_CFGEVAL_FLAG)
1838 report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1839 return (VSFR_CONTINUE); /* no parent entities */
1843 struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1845 if (debug & DEBUG_CFGEVAL_FLAG)
1846 report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1847 PA_MEMBERSHIP(membership));
1849 entity = value_scan_forward(membership);
1851 if (debug & DEBUG_CFGEVAL_FLAG)
1852 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1855 vsfr=(*func)(entity,func_data);
1857 if (debug & DEBUG_CFGEVAL_FLAG)
1858 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1859 PA_ENTITY(entity), PA_VSFR(vsfr));
1861 if (vsfr == VSFR_FOUND) {
1862 if (debug & DEBUG_CFGEVAL_FLAG)
1863 report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1866 if (vsfr == VSFR_CONTINUE)
1867 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1869 if (!entity || vsfr == VSFR_STOP) {
1870 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1872 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1874 if (debug & DEBUG_CFGEVAL_FLAG)
1875 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1876 PA_ENTITY(parent_entity), PA_ENTITY(entity));
1878 membership_node = tac_list_node_next(&membership->child_node);
1881 while (!membership_node) {
1882 membership = value_scan_backward(entity);
1884 if (debug & DEBUG_CFGEVAL_FLAG)
1885 report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1886 return (VSFR_CONTINUE); /* FINISH */
1889 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1891 if (debug & DEBUG_CFGEVAL_FLAG)
1892 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1893 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1894 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1896 membership_node = tac_list_node_next(&membership->child_node);