Release bumped to "gts4".
[tac_plus.git] / cfgeval.c
1 /*
2  * ???():
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.
6  *
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.
15  *
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.
19  */
20
21
22 #include "tac_plus.h"
23
24 #include <stdlib.h>
25
26 #include "cfgeval.h"
27 #include "cfgfile.h"
28 #include "main.h"
29 #include "parse.h"
30 #include "report.h"
31 #include "hash.h"
32
33
34 /* Configurable:
35  */
36
37 /* Whether to do sanity checks */
38 #define SCAN_PARANOIA 1
39
40 /* report even no-op scan up-to-date checks */
41 #define REPORT_CHECK_SCAN_VERBOSE 0
42
43
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));
49
50
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;
59
60
61 /* 'P[FA]_*' object printing section:
62  */
63
64 static const char *eval_result_to_string TAC_ARGS((int valid, enum eval_result er));
65
66 const char *
67 eval_result_to_string(valid, er)
68 int valid;
69 enum eval_result er;
70 {
71     if (!valid)
72         return ("!UPDATED");
73
74     switch (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 ***");
79     }
80     /* NOTREACHED */
81 }
82
83 static const char *value_scan_func_result_to_string TAC_ARGS((enum value_scan_func_result vsfr));
84
85 const char *
86 value_scan_func_result_to_string(vsfr)
87 enum value_scan_func_result vsfr;
88 {
89     switch (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 ***");
94     }
95     /* NOTREACHED */
96 }
97
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).
101  */
102
103 #define PF_VSFR       "%s"
104 #define PA_VSFR(vsfr) (value_scan_func_result_to_string((vsfr)))
105
106 #define PF_RESULT         "%s"
107 #define PA_RESULT(result) (eval_result_to_string(1 /* valid */, (result)))
108
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*"
114
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))
121
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))
126
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))))
130
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)
135
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)
142
143
144 /* '{unlink,free}_*()' section:
145  */
146
147 void unlink_expr TAC_ARGS((struct expr *expr));
148
149 /* never depend on "->parent" as it may not yet been filled! */
150 void
151 unlink_expr(expr)
152 struct expr *expr;
153 {
154     if (!expr)
155         return;         /* prevent possible DEBUG_CLEAN_FLAG report */
156
157     if (debug & DEBUG_CLEAN_FLAG) {
158         if (expr->membership)
159             report(LOG_DEBUG, "unlink_expr: (of membership): " PF_EXPR,
160                     PA_EXPR(expr));
161         else
162             report(LOG_DEBUG, "unlink_expr: (standalone)");
163     }
164
165     while (expr) {
166
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 */
170
171         switch (expr->type) {
172
173         case S_not:
174             unlink_expr(expr->u.not.child);
175             break;
176
177         case S_and:
178         case S_or:
179             unlink_expr(expr->u.and_or.child_first);
180             break;
181
182         case S_user:
183         case S_host:
184         case S_group:
185             break;
186
187         default:
188             report(LOG_ERR, "Illegal node type %d for unlink_expr", expr->type);
189             return;
190         }
191
192         expr = expr->next;
193     }
194 }
195
196 void free_expr TAC_ARGS((struct expr *expr));
197
198 /* given 'expr' memory WILL be freed! */
199 /* never depend on "->parent" as it may not yet been filled! */
200 void
201 free_expr(expr)
202 struct expr *expr;
203 {
204 struct expr *expr_next;
205
206     if (!expr)
207         return;         /* prevent possible DEBUG_CLEAN_FLAG report */
208
209     if (debug & DEBUG_CLEAN_FLAG)
210         report(LOG_DEBUG, "free_expr: (may be unlinked)");
211
212     while (expr) {
213         expr_next = expr->next;
214         switch (expr->type) {
215
216         case S_not:
217             free_expr(expr->u.not.child);
218             break;
219
220         case S_and:
221         case S_or:
222             free_expr(expr->u.and_or.child_first);
223             break;
224
225         case S_user:
226         case S_host:
227         case S_group:
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 */
231             break;
232
233         default:
234             report(LOG_ERR, "Illegal node type %d for free_expr", expr->type);
235             return;
236         }
237
238         free(expr);
239         expr=expr_next;
240     }
241 }
242
243 static void unlink_membership TAC_ARGS((struct membership *membership));
244
245 static void
246 unlink_membership(membership)
247 struct membership *membership;
248 {
249     ENTITY *parent_entity;
250
251     if (debug & DEBUG_CFGEVAL_FLAG)
252         report(LOG_DEBUG, "unlink_membership: " PF_MEMBERSHIP,
253                 PA_MEMBERSHIP(membership));
254
255     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
256
257     /* 'unlink_expr()' may want a lot of existing (linked) resources */
258     unlink_expr(membership->when);
259
260     check_request_scan_membership(membership, 1);       /* invalidate */
261     check_eval_scan_membership(membership, 1);          /* invalidate */
262
263 #ifdef SCAN_PARANOIA
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++;
267     }
268 #endif
269     parent_entity->to_child_membership_num--;
270
271     tac_list_node_remove(&membership->parent_node);
272     tac_list_node_remove(&membership-> child_node);
273 }
274
275 /* given 'membership' memory WILL be freed! */
276
277 static void free_membership TAC_ARGS((struct membership *membership));
278
279 static void
280 free_membership(membership)
281 struct membership *membership;
282 {
283     if (debug & DEBUG_CLEAN_FLAG)
284         report(LOG_DEBUG, "free_membership: (may be unlinked)");
285
286     free_expr(membership->when);
287     free(membership);
288 }
289
290 /* we are not allowed to free memory here, we are only 'scan_' additional 'free' */
291
292 void scan_free_entity TAC_ARGS((ENTITY *entity));
293
294 void
295 scan_free_entity(entity)
296 ENTITY *entity;
297 {
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;
302
303     if (debug & DEBUG_CLEAN_FLAG)
304         report(LOG_DEBUG, "scan_free_entity: " PF_ENTITY,
305                 PA_ENTITY(entity));
306
307     /* Be careful to keep '->next' ptr before we destroy the structure! */
308
309     for (
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
313             ) {
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);
318     }
319     for (
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
323             ) {
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);
328     }
329 }
330
331 struct expr *new_expr TAC_ARGS((int type));
332
333 struct expr *
334 new_expr(type)
335 int type;
336 {
337     struct expr *expr;
338
339     expr = (struct expr *) tac_malloc(sizeof(struct expr));
340     expr->next = NULL;
341     expr->type = type;
342     switch (expr->type) {
343
344     case S_not:
345         expr->u.not.child = NULL;
346         break;
347
348     case S_and:
349     case S_or:
350         expr->u.and_or.child_first = NULL;
351         break;
352
353     case S_user:
354     case S_host:
355     case S_group:
356         expr->u.entity.entity = NULL;
357         break;
358
359     default:
360         report(LOG_ERR, "Illegal node type %d for new_expr", expr->type);
361         return (expr);  /* it would be probably lethal to return NULL */
362     }
363     return (expr);
364 }
365
366 static int expr_sink_internal TAC_ARGS((struct expr *expr, struct membership *membership, struct expr *parent));
367
368 static int
369 expr_sink_internal(expr, membership, parent)
370 struct expr *expr;
371 struct membership *membership;
372 struct expr *parent;
373 {
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) {
380
381         case S_not:
382             if (expr_sink_internal(expr->u.not.child, membership, expr /* parent */))
383                 return (1);
384             break;
385
386         case S_and:
387         case S_or:
388             if (expr_sink_internal(expr->u.and_or.child_first, membership, expr /* parent */))
389                 return (1);
390             break;
391
392         case S_user:
393         case S_host:
394         case S_group:
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)
400                     return (1);
401                 expr->u.entity.name = NULL;
402             }
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);
406                 return (1);
407             }
408             /* already NULLed for not-yet-existing S_host */
409             free((char *) expr->u.entity.name);
410             expr->u.entity.name = NULL;
411             break;
412
413         default:
414             report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
415             return (1);
416         }
417     }
418     return (0);
419 }
420
421 static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
422
423 static int
424 expr_sink(expr, membership)
425 struct expr *expr;
426 struct membership *membership;
427 {
428     return (expr_sink_internal(expr, membership, NULL /* parent */));
429 }
430
431 static struct expr *expr_sink_register_head = NULL;
432
433 void expr_sink_register TAC_ARGS((struct expr *expr));
434
435 void
436 expr_sink_register(expr)
437 struct expr *expr;
438 {
439     if (!expr)
440         return;
441
442     expr->parent = expr_sink_register_head;
443     expr_sink_register_head = expr;
444 }
445
446 int expr_sink_commit TAC_ARGS((void));
447
448 int
449 expr_sink_commit()
450 {
451     struct expr *expr;
452
453     while ((expr = expr_sink_register_head)) {
454         expr_sink_register_head = expr->parent;
455         /* 'expr->parent' not defined for 'expr_sink()' */
456
457         if (expr_sink(expr, NULL /* membership */))
458             return (1);         /* failure */
459     }
460     return (0);         /* success */
461 }
462
463 struct expr *dupl_expr TAC_ARGS((const struct expr *in));
464
465 struct expr *
466 dupl_expr(in)
467 const struct expr *in;
468 {
469     struct expr *expr_root = NULL;
470     struct expr **succ_exprp = &expr_root;
471     struct expr *expr;
472
473     for (;in; in=in->next) {
474         expr = (struct expr *) tac_malloc(sizeof(struct expr));
475         expr->line = in->line;
476         expr->next = NULL;
477         expr->type = in->type;
478         switch (in->type) {
479
480         case S_not:
481             if (in->u.not.child && in->u.not.child->type==S_not) {
482                 free(expr);
483                 expr = dupl_expr(in->u.not.child->u.not.child);
484             } else
485                 expr->u.not.child = dupl_expr(in->u.not.child);
486             break;
487
488         case S_and:
489         case S_or:
490             if (!in->u.and_or.child_first) {
491                 free(expr);
492                 continue;
493             } else if (!in->u.and_or.child_first->next) {
494                 free(expr);
495                 expr = dupl_expr(in->u.and_or.child_first);
496             } else
497                 expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
498             break;
499
500         case S_user:
501         case S_host:
502         case S_group:
503             if (in->u.entity.name)
504                 expr->u.entity.name = tac_strdup(in->u.entity.name);
505             else
506                 expr->u.entity.name = NULL;
507             expr->u.entity.entity = in->u.entity.entity;
508             break;
509
510         default:
511             report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
512             free_expr(expr_root);
513             return (NULL);
514         }
515
516         *succ_exprp = expr;
517         succ_exprp = &expr->next;
518     }
519     return (expr_root);
520 }
521
522
523 /* 'check_*_scan_*()' section:
524  */
525
526 static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
527
528 static void
529 check_request_scan_expr(expr, flush)
530 struct expr *expr;
531 int flush;
532 {
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));
537 #endif
538
539     if (!flush && expr->request_scan.seq == request_scan_seq)
540         return;         /* up to date */
541
542     expr->request_scan.result = ER_UNKNOWN;
543     expr->request_scan.loop_reported = 0;
544     expr->request_scan.seq = request_scan_seq;
545
546     if (debug & DEBUG_CFGEVAL_FLAG)
547         report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
548                 PA_EXPR(expr));
549 }
550
551 static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
552
553 static void
554 check_eval_scan_expr(expr, flush)
555 struct expr *expr;
556 int flush;
557 {
558 #if REPORT_CHECK_SCAN_VERBOSE
559     if (debug & DEBUG_CFGEVAL_FLAG)
560         report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
561                 PA_EXPR(expr));
562 #endif
563
564     if (!flush && expr->eval_scan.seq == eval_scan_seq)
565         return;         /* up to date */
566     check_request_scan_expr(expr, 0);
567
568     switch (expr->type) {
569
570     case S_user:
571     case S_host:
572     case S_group: {
573 #ifdef SCAN_PARANOIA
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);
578
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);
584             }
585 #else /* SCAN_PARANOIA */
586         tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
587 #endif /* SCAN_PARANOIA */
588         } break;
589     }
590
591     expr->eval_scan.seq = eval_scan_seq;        /* used above, keep as LAST! */
592
593     if (debug & DEBUG_CFGEVAL_FLAG)
594         report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
595                 PA_EXPR(expr));
596 }
597
598 static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
599
600 static void
601 check_request_scan_membership(membership, flush)
602 struct membership *membership;
603 int flush;
604 {
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));
609 #endif
610
611     if (!flush && membership->request_scan.seq == request_scan_seq)
612         return;         /* up to date */
613
614 #ifdef SCAN_PARANOIA
615     {
616         struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
617
618         if (virtual_list && virtual_list != &request_virtual_membership_list)
619             report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
620         if (virtual_list)
621             tac_list_node_remove(&membership->request_scan.virtual_membership_node);
622     }
623 #else /* SCAN_PARANOIA */
624     tac_list_node_init(&membership->request_scan.virtual_membership_node);
625 #endif /* SCAN_PARANOIA */
626
627     membership->request_scan.seq = request_scan_seq;    /* used above, keep as LAST! */
628
629     if (debug & DEBUG_CFGEVAL_FLAG)
630         report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
631                 PA_MEMBERSHIP(membership));
632 }
633
634 /* we are cross-checking (membership<->parent entity)! */
635
636 static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
637
638 static void
639 check_eval_scan_membership(membership, flush)
640 struct membership *membership;
641 int flush;
642 {
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));
647 #endif
648
649     if (!flush && membership->eval_scan.seq == eval_scan_seq)
650         return;         /* up to date */
651     check_request_scan_membership(membership, 0);
652
653     membership->eval_scan.unsolved = 1;
654     membership->eval_scan.seq = eval_scan_seq;
655
656     if (debug & DEBUG_CFGEVAL_FLAG)
657         report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
658                 PA_MEMBERSHIP(membership));
659 }
660
661 static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
662
663 static void
664 check_request_scan_entity(entity, flush)
665 ENTITY *entity;
666 int flush;
667 {
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));
672 #endif
673
674     if (!flush && entity->request_scan.seq == request_scan_seq)
675         return;
676
677     entity->request_scan.belongs = ER_UNKNOWN;
678     entity->request_scan.seq = request_scan_seq;
679
680     if (debug & DEBUG_CFGEVAL_FLAG)
681         report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
682                 PA_ENTITY(entity));
683 }
684
685 static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
686
687 static void
688 check_value_scan_entity(entity, flush)
689 ENTITY *entity;
690 int flush;
691 {
692 #if REPORT_CHECK_SCAN_VERBOSE
693     if (debug & DEBUG_CFGEVAL_FLAG)
694         report(LOG_DEBUG, "check_value_scan_entity: " PF_ENTITY,
695                 PA_ENTITY(entity));
696 #endif
697
698     if (!flush && entity->value_scan.seq == value_scan_seq)
699         return;
700     check_request_scan_entity(entity, 0);
701
702     entity->value_scan.seen = 0;
703     entity->value_scan.from = NULL;
704     entity->value_scan.seq = value_scan_seq;
705
706     if (debug & DEBUG_CFGEVAL_FLAG)
707         report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
708                 PA_ENTITY(entity));
709 }
710
711 static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
712
713 static void
714 check_eval_scan_entity(entity, flush)
715 ENTITY *entity;
716 int flush;
717 {
718     struct tac_list_node *child_membership_parent_node;
719
720 #if REPORT_CHECK_SCAN_VERBOSE
721     if (debug & DEBUG_CFGEVAL_FLAG)
722         report(LOG_DEBUG, "check_eval_scan_entity: " PF_ENTITY,
723                 PA_ENTITY(entity));
724 #endif
725
726     if (!flush && entity->eval_scan.seq == eval_scan_seq)
727         return;         /* up to date */
728     check_value_scan_entity(entity, 0);
729
730     entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
731
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);
734
735         entity->eval_scan.unsolved_to_child_membership_first = child_membership;
736     } else
737         entity->eval_scan.unsolved_to_child_membership_first = NULL;
738
739 #ifdef SCAN_PARANOIA
740     {
741         struct tac_list_node *notify_expr_node;
742
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);
745
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);
751         }
752
753         if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
754             tac_list_node_remove(&entity->eval_scan.pending_entity_node);
755     }
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 */
760
761     entity->eval_scan.seq = eval_scan_seq;      /* used above, keep as LAST! */
762
763     if (debug & DEBUG_CFGEVAL_FLAG)
764         report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
765                 PA_ENTITY(entity));
766 }
767
768
769 /* invalidation managing section (for '*_scan_begin()'):
770  */
771
772 /* this will happen once upon 'unsigned' overflow, ehm */
773
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))
778
779 static const long invalidate_scan_expr_table[IS_MAX]={
780     G_STRUCT_OFFSET(struct expr, request_scan.seq),
781     -1,
782     G_STRUCT_OFFSET(struct expr,    eval_scan.seq)};
783
784 static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
785
786 static void
787 invalidate_scan_expr(expr_single, what)
788 struct expr *expr_single;
789 enum invalidate_scan what;
790 {
791     struct expr *expr_parent, *expr_child;
792
793     if (!expr_single) {
794         report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
795         return;
796     }
797     if (expr_single->parent) {
798         report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
799         return;
800     }
801
802     /* TOP->DOWN scanner: */
803 top_down:
804     do {
805         INVALIDATE_SEQ_PTR(expr,expr_single);
806         expr_parent = expr_single;
807
808         switch (expr_parent->type) {
809
810         case S_not:
811             expr_child = expr_parent->u.not.child;
812             continue;
813
814         case S_and:
815         case S_or:
816             expr_child = expr_parent->u.and_or.child_first;
817             break;
818
819         case S_user:
820         case S_host:
821         case S_group:
822             expr_child = NULL;  /* no child exists */
823             break;
824
825         default:
826             report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
827             return;
828         }
829     } while ((expr_single = expr_child));
830     /* expr_child==NULL, we have only expr_parent: */
831
832     expr_child = expr_parent;
833
834     /* we have only expr_child: */
835     /* BOTTOM->UP scanner */
836     do {
837         if ((expr_single = expr_child->next))
838             goto top_down;
839         expr_parent = expr_child->parent;
840     } while ((expr_child = expr_parent));
841 }
842
843 static const long invalidate_scan_membership_table[IS_MAX]={
844     G_STRUCT_OFFSET(struct membership, request_scan.seq),
845     -1,
846     G_STRUCT_OFFSET(struct membership,    eval_scan.seq)};
847
848 static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
849
850 static void
851 invalidate_scan_membership(membership, what)
852 struct membership *membership;
853 enum invalidate_scan what;
854 {
855     INVALIDATE_SEQ(membership);
856
857     if (membership->when)
858         invalidate_scan_expr(membership->when, what);
859 }
860
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)};
865
866 static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
867
868 static void
869 invalidate_scan_entity(entity, what)
870 ENTITY *entity;
871 enum invalidate_scan what;
872 {
873     struct tac_list_node *child_membership_node;
874     struct membership *child_membership;
875
876     INVALIDATE_SEQ(entity);
877
878     if (what==IS_VALUE)         /* optimalization */
879         return;
880
881     for (
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)
885             ) {
886         child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
887         invalidate_scan_membership(child_membership, what);
888     }
889 }
890
891 void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
892
893 void
894 scan_invalidate_entities_hashtable(hashtable, what)
895 void **hashtable;
896 enum invalidate_scan what;
897 {
898     int i;
899     ENTITY *entity;
900
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);
904 }
905
906 /* '*_scan_begin()' section:
907  */
908
909 void request_scan_begin TAC_ARGS((void));
910
911 void
912 request_scan_begin()
913 {
914 #ifdef SCAN_PARANOIA
915     static int inited = 0;
916 #endif /* SCAN_PARANOIA */
917
918     if (debug & DEBUG_CFGEVAL_FLAG)
919         report(LOG_DEBUG, "request_scan_begin:");
920
921     request_scan_user_known = 0;
922
923     if (!++request_scan_seq)
924         scan_invalidate_entities(IS_REQUEST);
925
926 #ifdef SCAN_PARANOIA
927     if (!inited) {
928 #endif /* SCAN_PARANOIA */
929         tac_list_init(&request_virtual_membership_list);
930 #ifdef SCAN_PARANOIA
931         inited = 1;
932     } else {
933         struct tac_list_node *virtual_membership_node;
934
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);
937
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);
943             }
944     }
945 #endif /* SCAN_PARANOIA */
946 }
947
948 static void value_scan_begin TAC_ARGS((ENTITY *entity));
949
950 static void
951 value_scan_begin(entity)
952 ENTITY *entity;
953 {
954     if (debug & DEBUG_CFGEVAL_FLAG)
955         report(LOG_DEBUG, "value_scan_begin:");
956
957     if (!++value_scan_seq)
958         scan_invalidate_entities(IS_VALUE);
959
960     check_value_scan_entity(entity, 0); /* sure as seq invalidated */
961     /* assumed (entity->value_scan.from == NULL) */
962 }
963
964 #ifdef SCAN_PARANOIA
965
966 static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
967
968 static void
969 eval_scan_begin_pending_entity_node(pending_entity_node)
970 struct tac_list_node *pending_entity_node;
971 {
972     ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
973
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");
976
977     tac_list_node_remove(pending_entity_node);
978 }
979
980 #endif /* SCAN_PARANOIA */
981
982 static void eval_scan_begin TAC_ARGS((void));
983
984 static void
985 eval_scan_begin()
986 {
987 #ifdef SCAN_PARANOIA
988     static int inited = 0;
989 #endif /* SCAN_PARANOIA */
990
991     if (debug & DEBUG_CFGEVAL_FLAG)
992         report(LOG_DEBUG, "eval_scan_begin:");
993
994     if (!++eval_scan_seq)
995         scan_invalidate_entities(IS_EVAL);
996
997 #ifdef SCAN_PARANOIA
998     if (!inited) {
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
1004         inited = 1;
1005     } else {
1006         struct tac_list_node *pending_entity_node;
1007         struct tac_list_node *notify_expr_node;
1008
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);
1013
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);
1016
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");
1019
1020             tac_list_node_remove(notify_expr_node);
1021         }
1022     }
1023 #endif /* SCAN_PARANOIA */
1024 }
1025
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...
1030  */
1031
1032 static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
1033
1034 static void register_kicked_entity(entity, priority)
1035 ENTITY *entity;
1036 int priority;
1037 {
1038     struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1039
1040     check_eval_scan_entity(entity, 0);
1041
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",
1046                     PA_ENTITY(entity));
1047     }
1048     if (tac_list_node_get_list(pending_entity_node) == NULL) {
1049         if (priority)
1050             tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
1051         else
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"));
1056     }
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");
1060         return;
1061     }
1062 #endif
1063 }
1064
1065 /* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
1066
1067 static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
1068
1069 static void
1070 expr_eval_notify_expr(expr)
1071 struct expr *expr;
1072 {
1073     ENTITY *entity = expr->u.entity.entity;
1074
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));
1078
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));
1085 #endif
1086         return;
1087     }
1088
1089     tac_list_addtail(&entity->eval_scan.notify_expr_list,
1090             &expr->eval_scan.u.entity.notify_expr_node);
1091
1092     register_kicked_entity(entity, 0 /* priority */);
1093 }
1094
1095 /* check_eval_scan_*() is assumed for "expr" ! */
1096
1097 static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
1098
1099 static void
1100 expr_eval_notify_expr_remove_internal(expr)
1101 struct expr *expr;
1102 {
1103     if (debug & DEBUG_CFGEVAL_FLAG)
1104         report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
1105                 PA_EXPR(expr));
1106
1107     if (!expr)
1108         return;
1109     if (expr->eval_scan.seq != eval_scan_seq)
1110         return;
1111     if (expr->request_scan.result != ER_UNKNOWN)
1112         return;
1113
1114     switch (expr->type) {
1115
1116     case S_not:
1117         expr_eval_notify_expr_remove_internal(expr->u.not.child);
1118         break;
1119
1120     case S_and:
1121     case S_or: {
1122         struct expr *child;
1123
1124         for (child=expr->u.and_or.child_first; child; child=child->next)
1125             expr_eval_notify_expr_remove_internal(child);
1126         } break;
1127
1128     case S_user:
1129     case S_host:
1130     case S_group: {
1131         ENTITY *entity = expr->u.entity.entity;
1132         struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1133
1134         if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1135             break;
1136
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))
1139             break;
1140         /* no one is further interested in "entity" */
1141
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",
1146                         PA_ENTITY(entity));
1147         }
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",
1152                         PA_ENTITY(entity));
1153         }
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");
1157             return;
1158         }
1159 #endif
1160
1161         } break;
1162
1163     default:
1164         report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
1165         return;
1166     }
1167 }
1168
1169 static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
1170
1171 static void expr_eval_notify_expr_flush_destroy_entity_list()
1172 {
1173 struct tac_list_node *destroy_entity_node;
1174
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;
1178
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));
1182
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);
1185
1186             expr_eval_notify_expr_remove_internal(destroy_notify_expr);
1187         }
1188     }
1189 }
1190
1191 static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
1192
1193 static void
1194 expr_eval_notify_expr_remove(expr)
1195 struct expr *expr;
1196 {
1197     if (debug & DEBUG_CFGEVAL_FLAG)
1198         report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
1199                 PA_EXPR(expr));
1200
1201     expr_eval_notify_expr_remove_internal(expr);
1202     expr_eval_notify_expr_flush_destroy_entity_list();
1203 }
1204
1205 /* It would be very nice to try to optimize the expression before evaluation.
1206
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.
1212
1213    TODO in future: Full NP optimization for small number of variables and/or
1214    heuristic optimizations for complex expressions.
1215 */
1216
1217 static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
1218
1219 static enum eval_result
1220 expr_eval_immediate(expr_single)
1221 struct expr *expr_single;
1222 {
1223     struct expr *expr_child, *expr_parent;
1224     enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
1225
1226     if (debug & DEBUG_CFGEVAL_FLAG)
1227         report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
1228                 PA_EXPR(expr_single));
1229
1230     if (!expr_single)
1231         return (ER_TRUE);
1232
1233     /* TOP->DOWN scanner: */
1234 top_down:
1235     while (1) {
1236         enum eval_result result_single;
1237
1238         if (debug & DEBUG_CFGEVAL_FLAG)
1239             report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
1240                     PA_EXPR(expr_single));
1241
1242         check_eval_scan_expr(expr_single, 0);
1243         result_single = expr_single->request_scan.result;
1244         if (result_single != ER_UNKNOWN)
1245             break;
1246         switch (expr_single->type) {
1247
1248         case S_not:
1249             expr_single = expr_single->u.not.child;
1250             continue;
1251
1252         case S_and:
1253         case S_or:
1254             expr_single = expr_single->u.and_or.child_first;
1255             continue;
1256
1257         case S_user:
1258         case S_host:
1259         case S_group: {
1260             ENTITY *entity = expr_single->u.entity.entity;
1261
1262             check_eval_scan_entity(entity, 0);
1263
1264             if (entity->request_scan.belongs == ER_UNKNOWN)
1265                 expr_eval_notify_expr(expr_single);
1266             else
1267                 result_single = entity->request_scan.belongs;
1268             } break;
1269
1270         default:
1271             report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
1272             return (ER_UNKNOWN);
1273         }
1274
1275         expr_single->request_scan.result = result_single;
1276         break;
1277     }
1278
1279     /* BOTTOM->UP scanner: */
1280     do {
1281         if (debug & DEBUG_CFGEVAL_FLAG)
1282             report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
1283                     PA_EXPR(expr_single));
1284
1285         expr_parent = expr_single->parent;
1286         if (!expr_parent)
1287             break;
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);
1291         }
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);
1295         }
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);
1299         }
1300
1301         expr_child = expr_single;
1302         result_child = expr_child->request_scan.result;
1303
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));
1307
1308         switch (expr_parent->type) {
1309
1310         case S_not:
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;
1315             }
1316             break;
1317
1318         case S_and:
1319         case S_or: {
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);
1322
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));
1331                     goto top_down;
1332                 }
1333
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));
1337
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.
1344                  */
1345                 result_parent = consent;
1346                 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1347                 {
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;
1353                         break;
1354                     }
1355                 }
1356                 break;
1357             }
1358             } break;
1359
1360         default:
1361             report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1362             return (ER_UNKNOWN);
1363         }
1364
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));
1368
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);
1373         }
1374
1375         expr_single = expr_parent;
1376     } while (0);
1377     /* The whole expression has been scanned to its root, we have "expr_single" */
1378
1379     if (debug & DEBUG_CFGEVAL_FLAG)
1380         report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1381                 PA_EXPR(expr_single));
1382
1383     return (expr_single->request_scan.result);
1384 }
1385
1386 static void membership_solved TAC_ARGS((struct membership *membership));
1387
1388 static void
1389 membership_solved(membership)
1390 struct membership *membership;
1391 {
1392     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1393
1394     check_request_scan_entity(parent_entity, 0);
1395
1396 #ifdef SCAN_PARANOIA
1397     if (!membership->eval_scan.unsolved) {
1398         report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1399         return;
1400     }
1401 #endif
1402
1403     membership->eval_scan.unsolved = 0;
1404
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++;
1409     }
1410 #endif
1411     parent_entity->eval_scan.unsolved_to_child_membership_num--;
1412
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 */);
1417     }
1418 }
1419
1420 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1421
1422 static void
1423 membership_parent_solve(membership, how)
1424 struct membership *membership;
1425 enum eval_result how;
1426 {
1427     enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1428     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1429
1430     check_request_scan_entity(parent_entity, 0);
1431
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));
1435
1436     parent_entity->request_scan.belongs = how;
1437     register_kicked_entity(parent_entity, 1 /* priority */);
1438
1439     membership_solved(membership);
1440
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));
1444 }
1445
1446 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1447
1448 static void
1449 membership_eval_immediate(membership)
1450 struct membership *membership;
1451 {
1452     enum eval_result membership_valid;
1453     ENTITY *child_entity, *parent_entity;
1454
1455     if (debug & DEBUG_CFGEVAL_FLAG)
1456         report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1457                 PA_MEMBERSHIP(membership));
1458
1459     check_eval_scan_membership(membership, 0);
1460
1461     if (!membership->eval_scan.unsolved)
1462         return;
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? */
1466         return;
1467
1468     membership_valid = expr_eval_immediate(membership->when);
1469
1470     child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1471     check_request_scan_entity( child_entity, 0);
1472
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);
1476         return;
1477     }
1478 #endif
1479
1480     if (child_entity->request_scan.belongs == ER_TRUE  && membership_valid == ER_TRUE ) {
1481         membership_parent_solve(membership, ER_TRUE );
1482         return;
1483     }
1484
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 */);
1489
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);
1493
1494     if (debug & DEBUG_CFGEVAL_FLAG)
1495         report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1496                 PA_MEMBERSHIP(membership));
1497 }
1498
1499 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1500
1501 static void
1502 entity_eval_immediate(entity)
1503 ENTITY *entity;
1504 {
1505     struct tac_list_node *notified_expr_node;
1506     struct tac_list_node *child_membership_node;
1507
1508     if (debug & DEBUG_CFGEVAL_FLAG)
1509         report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1510                 PA_ENTITY(entity));
1511
1512     check_eval_scan_entity(entity, 0);
1513
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",
1518                     PA_ENTITY(entity));
1519 #endif
1520         return;
1521     }
1522
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);
1527
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);
1531             else
1532                 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1533
1534             register_kicked_entity(entity, 0 /* priority */);
1535
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));
1539             return;
1540         }
1541
1542         if (!entity->eval_scan.unsolved_to_child_membership_num)
1543             entity->request_scan.belongs = ER_FALSE;
1544         else {
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");
1547             return;
1548         }
1549     }
1550     /* belonging is known here */
1551
1552     /* recheck all memberships we may decide */
1553     for (
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)
1557             ) {
1558         struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1559
1560         membership_eval_immediate(child_membership);
1561     }
1562
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);
1567     }
1568
1569     if (debug & DEBUG_CFGEVAL_FLAG)
1570         report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1571                 PA_ENTITY(entity));
1572 }
1573
1574
1575 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1576
1577 enum eval_result
1578 expr_eval(expr)
1579 struct expr *expr;
1580 {
1581     if (debug & DEBUG_CFGEVAL_FLAG)
1582         report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1583                 PA_EXPR(expr));
1584
1585     if (!expr)
1586         return (ER_TRUE);
1587
1588     eval_scan_begin();
1589     if (expr_eval_immediate(expr) != ER_UNKNOWN)
1590         return (expr->request_scan.result);
1591
1592     /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1593      * otherwise we may have no longer valid node!
1594      */
1595     for (;;) {
1596         struct tac_list_node *notified_expr_node, *kicked_entity_node;
1597
1598         /* check it rather always, checking just on notifications looks too complex.
1599         */
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",
1603                         PA_EXPR(expr));
1604             return (expr->request_scan.result);
1605         }
1606
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 */
1610
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);
1613
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));
1617
1618             tac_list_node_remove(notified_expr_node);
1619             expr_eval_immediate(notified_expr);
1620
1621             if (notified_expr->membership)
1622                 membership_eval_immediate(notified_expr->membership);
1623
1624             continue;           /* shortcut */
1625         }
1626
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);
1629
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));
1633
1634             tac_list_node_remove(kicked_entity_node);
1635             entity_eval_immediate(kicked_entity);
1636             continue;           /* shortcut */
1637         }
1638
1639         break;  /* nothing done yet, all lists are empty! */
1640     }
1641
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;
1645     }
1646     return (ER_UNKNOWN);
1647 }
1648
1649
1650 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1651
1652 void eval_force_belong_entity(entity)
1653 ENTITY *entity;
1654 {
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));
1658
1659     check_request_scan_entity(entity, 0);
1660
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");
1663
1664     entity->request_scan.belongs = ER_TRUE;
1665 }
1666
1667 void scan_init_entity TAC_ARGS((ENTITY *entity));
1668
1669 void
1670 scan_init_entity(entity)
1671 ENTITY *entity;
1672 {
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);
1678 }
1679
1680 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1681
1682 struct membership *
1683 enlist_entity_direct(parent, child, when)
1684 ENTITY *parent;
1685 ENTITY *child;
1686 struct expr *when;
1687 {
1688     struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1689
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;
1695
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);
1703         return (NULL);
1704     }
1705
1706     if (debug & DEBUG_CFGEVAL_FLAG)
1707         report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1708                 PA_MEMBERSHIP(membership));
1709
1710     return (membership);
1711 }
1712
1713 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1714
1715 struct membership *
1716 virtual_enlist_entity_direct(parent, child)
1717 ENTITY *parent;
1718 ENTITY *child;
1719 {
1720     struct membership *membership;
1721
1722     if (debug & DEBUG_CFGEVAL_FLAG)
1723         report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1724
1725     membership = enlist_entity_direct(parent, child, NULL /* when */);
1726     if (!membership)
1727         return (NULL);
1728
1729     check_request_scan_membership(membership, 0);
1730     tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1731
1732     return (membership);
1733 }
1734
1735 /* returns given 'entity' or NULL if already visited */
1736
1737 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1738
1739 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1740
1741 static ENTITY *
1742 value_scan_forward(membership)
1743 struct membership *membership;
1744 {
1745     ENTITY *parent_entity;
1746
1747     if (debug & DEBUG_CFGEVAL_FLAG)
1748         report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1749                 PA_MEMBERSHIP(membership));
1750
1751     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1752
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.");
1756         return (NULL);
1757     }
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);
1765         return (NULL);
1766     }
1767     parent_entity->value_scan.seen = 1;
1768     parent_entity->value_scan.from = membership;
1769
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);
1774 }
1775
1776 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1777
1778 struct membership *
1779 value_scan_backward(entity)
1780 ENTITY *entity;
1781 {
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));
1785
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");
1789         return (NULL);
1790     }
1791 #endif
1792
1793     return (entity->value_scan.from);
1794 }
1795
1796 /* Scan the entity graph and return each node found.
1797    'when' conditions for graph connections are respected,
1798    looping is correctly prevented.
1799 */
1800
1801 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1802
1803 enum value_scan_func_result
1804 value_scan_entity(entity, recurse, func, func_data)
1805 ENTITY *entity;
1806 int recurse;
1807 value_scan_func_t func;
1808 void *func_data;
1809 {
1810     enum value_scan_func_result vsfr;
1811     struct tac_list_node *membership_node;
1812
1813     if (debug & DEBUG_CFGEVAL_FLAG)
1814         report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1815                 PA_ENTITY(entity), recurse);
1816
1817     vsfr=(*func)(entity,func_data);
1818
1819     if (debug & DEBUG_CFGEVAL_FLAG)
1820         report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1821                 PA_VSFR(vsfr));
1822
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");
1826         return (vsfr);
1827     }
1828     if (!recurse ) {
1829         if (debug & DEBUG_CFGEVAL_FLAG)
1830             report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1831         return (VSFR_STOP);
1832     }
1833
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 */
1840     }
1841
1842     while (1) {
1843         struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1844
1845         if (debug & DEBUG_CFGEVAL_FLAG)
1846             report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1847                     PA_MEMBERSHIP(membership));
1848
1849         entity = value_scan_forward(membership);
1850         if (entity) {
1851             if (debug & DEBUG_CFGEVAL_FLAG)
1852                 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1853                         PA_ENTITY(entity));
1854
1855             vsfr=(*func)(entity,func_data);
1856
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));
1860
1861             if (vsfr == VSFR_FOUND) {
1862                 if (debug & DEBUG_CFGEVAL_FLAG)
1863                     report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1864                 return (vsfr);
1865             }
1866             if (vsfr == VSFR_CONTINUE)
1867                 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1868         }
1869         if (!entity || vsfr == VSFR_STOP) {
1870             ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1871
1872             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1873
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));
1877
1878             membership_node = tac_list_node_next(&membership->child_node);
1879         }
1880
1881         while (!membership_node) {
1882             membership = value_scan_backward(entity);
1883             if (!membership) {
1884                 if (debug & DEBUG_CFGEVAL_FLAG)
1885                     report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1886                 return (VSFR_CONTINUE);         /* FINISH */
1887             }
1888
1889             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1890
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));
1895
1896             membership_node = tac_list_node_next(&membership->child_node);
1897         }
1898     }
1899     /* NOTREACHED */
1900 }