"referenced entity .* not found" message fixed to be fatal
[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) {
398                 report(LOG_ERR, "referenced entity %s %s not found on line %d",
399                         entity_type_to_string(expr->type), expr->u.entity.name, expr->line);
400                 return (1);
401                 }
402             free((char *) expr->u.entity.name);
403             expr->u.entity.name = NULL;
404             break;
405
406         default:
407             report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
408             return (1);
409         }
410     }
411     return (0);
412 }
413
414 static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
415
416 static int
417 expr_sink(expr, membership)
418 struct expr *expr;
419 struct membership *membership;
420 {
421     return (expr_sink_internal(expr, membership, NULL /* parent */));
422 }
423
424 static struct expr *expr_sink_register_head = NULL;
425
426 void expr_sink_register TAC_ARGS((struct expr *expr));
427
428 void
429 expr_sink_register(expr)
430 struct expr *expr;
431 {
432     if (!expr)
433         return;
434
435     expr->parent = expr_sink_register_head;
436     expr_sink_register_head = expr;
437 }
438
439 int expr_sink_commit TAC_ARGS((void));
440
441 int
442 expr_sink_commit()
443 {
444     struct expr *expr;
445
446     while ((expr = expr_sink_register_head)) {
447         expr_sink_register_head = expr->parent;
448         /* 'expr->parent' not defined for 'expr_sink()' */
449
450         if (expr_sink(expr, NULL /* membership */))
451             return (1);         /* failure */
452     }
453     return (0);         /* success */
454 }
455
456 struct expr *dupl_expr TAC_ARGS((const struct expr *in));
457
458 struct expr *
459 dupl_expr(in)
460 const struct expr *in;
461 {
462     struct expr *expr_root = NULL;
463     struct expr **succ_exprp = &expr_root;
464     struct expr *expr;
465
466     for (;in; in=in->next) {
467         expr = (struct expr *) tac_malloc(sizeof(struct expr));
468         expr->line = in->line;
469         expr->next = NULL;
470         expr->type = in->type;
471         switch (in->type) {
472
473         case S_not:
474             if (in->u.not.child && in->u.not.child->type==S_not) {
475                 free(expr);
476                 expr = dupl_expr(in->u.not.child->u.not.child);
477             } else
478                 expr->u.not.child = dupl_expr(in->u.not.child);
479             break;
480
481         case S_and:
482         case S_or:
483             if (!in->u.and_or.child_first) {
484                 free(expr);
485                 continue;
486             } else if (!in->u.and_or.child_first->next) {
487                 free(expr);
488                 expr = dupl_expr(in->u.and_or.child_first);
489             } else
490                 expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
491             break;
492
493         case S_user:
494         case S_host:
495         case S_group:
496             if (in->u.entity.name)
497                 expr->u.entity.name = tac_strdup(in->u.entity.name);
498             else
499                 expr->u.entity.name = NULL;
500             expr->u.entity.entity = in->u.entity.entity;
501             break;
502
503         default:
504             report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
505             free_expr(expr_root);
506             return (NULL);
507         }
508
509         *succ_exprp = expr;
510         succ_exprp = &expr->next;
511     }
512     return (expr_root);
513 }
514
515
516 /* 'check_*_scan_*()' section:
517  */
518
519 static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
520
521 static void
522 check_request_scan_expr(expr, flush)
523 struct expr *expr;
524 int flush;
525 {
526 #if REPORT_CHECK_SCAN_VERBOSE
527     if (debug & DEBUG_CFGEVAL_FLAG)
528         report(LOG_DEBUG, "check_request_scan_expr: " PF_EXPR " (" PF_ERESULT_EXPR ")",
529                 PA_EXPR(expr), PA_ERESULT_EXPR(expr));
530 #endif
531
532     if (!flush && expr->request_scan.seq == request_scan_seq)
533         return;         /* up to date */
534
535     expr->request_scan.result = ER_UNKNOWN;
536     expr->request_scan.loop_reported = 0;
537     expr->request_scan.seq = request_scan_seq;
538
539     if (debug & DEBUG_CFGEVAL_FLAG)
540         report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
541                 PA_EXPR(expr));
542 }
543
544 static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
545
546 static void
547 check_eval_scan_expr(expr, flush)
548 struct expr *expr;
549 int flush;
550 {
551 #if REPORT_CHECK_SCAN_VERBOSE
552     if (debug & DEBUG_CFGEVAL_FLAG)
553         report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
554                 PA_EXPR(expr));
555 #endif
556
557     if (!flush && expr->eval_scan.seq == eval_scan_seq)
558         return;         /* up to date */
559     check_request_scan_expr(expr, 0);
560
561     switch (expr->type) {
562
563     case S_user:
564     case S_host:
565     case S_group: {
566 #ifdef SCAN_PARANOIA
567                if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node) == &eval_notified_expr_list) {
568             report(LOG_ERR, "INTERNAL: expr still connected to eval_notified_expr_list in check_eval_scan_expr");
569         } else if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
570             ENTITY *notifying_entity = EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr);
571
572             if (notifying_entity != expr->u.entity.entity)
573                 report(LOG_ERR, "INTERNAL: expr->notify_expr_node->list != expr->entity");
574             if (notifying_entity->eval_scan.seq != expr->eval_scan.seq)
575                 report(LOG_ERR, "INTERNAL: entity seq != expr node seq");
576             tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
577             }
578 #else /* SCAN_PARANOIA */
579         tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
580 #endif /* SCAN_PARANOIA */
581         } break;
582     }
583
584     expr->eval_scan.seq = eval_scan_seq;        /* used above, keep as LAST! */
585
586     if (debug & DEBUG_CFGEVAL_FLAG)
587         report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
588                 PA_EXPR(expr));
589 }
590
591 static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
592
593 static void
594 check_request_scan_membership(membership, flush)
595 struct membership *membership;
596 int flush;
597 {
598 #if REPORT_CHECK_SCAN_VERBOSE
599     if (debug & DEBUG_CFGEVAL_FLAG)
600         report(LOG_DEBUG, "check_request_scan_membership: " PF_MEMBERSHIP " (" PF_ERESULT_MEMBERSHIP ")",
601                 PA_MEMBERSHIP(membership), PA_ERESULT_MEMBERSHIP(membership));
602 #endif
603
604     if (!flush && membership->request_scan.seq == request_scan_seq)
605         return;         /* up to date */
606
607 #ifdef SCAN_PARANOIA
608     {
609         struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
610
611         if (virtual_list && virtual_list != &request_virtual_membership_list)
612             report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
613         if (virtual_list)
614             tac_list_node_remove(&membership->request_scan.virtual_membership_node);
615     }
616 #else /* SCAN_PARANOIA */
617     tac_list_node_init(&membership->request_scan.virtual_membership_node);
618 #endif /* SCAN_PARANOIA */
619
620     membership->request_scan.seq = request_scan_seq;    /* used above, keep as LAST! */
621
622     if (debug & DEBUG_CFGEVAL_FLAG)
623         report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
624                 PA_MEMBERSHIP(membership));
625 }
626
627 /* we are cross-checking (membership<->parent entity)! */
628
629 static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
630
631 static void
632 check_eval_scan_membership(membership, flush)
633 struct membership *membership;
634 int flush;
635 {
636 #if REPORT_CHECK_SCAN_VERBOSE
637     if (debug & DEBUG_CFGEVAL_FLAG)
638         report(LOG_DEBUG, "check_eval_scan_membership: " PF_MEMBERSHIP,
639                 PA_MEMBERSHIP(membership));
640 #endif
641
642     if (!flush && membership->eval_scan.seq == eval_scan_seq)
643         return;         /* up to date */
644     check_request_scan_membership(membership, 0);
645
646     membership->eval_scan.unsolved = 1;
647     membership->eval_scan.seq = eval_scan_seq;
648
649     if (debug & DEBUG_CFGEVAL_FLAG)
650         report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
651                 PA_MEMBERSHIP(membership));
652 }
653
654 static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
655
656 static void
657 check_request_scan_entity(entity, flush)
658 ENTITY *entity;
659 int flush;
660 {
661 #if REPORT_CHECK_SCAN_VERBOSE
662     if (debug & DEBUG_CFGEVAL_FLAG)
663         report(LOG_DEBUG, "check_request_scan_entity: " PF_ENTITY " (" PF_ERESULT_ENTITY ")",
664                 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
665 #endif
666
667     if (!flush && entity->request_scan.seq == request_scan_seq)
668         return;
669
670     entity->request_scan.belongs = ER_UNKNOWN;
671     entity->request_scan.seq = request_scan_seq;
672
673     if (debug & DEBUG_CFGEVAL_FLAG)
674         report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
675                 PA_ENTITY(entity));
676 }
677
678 static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
679
680 static void
681 check_value_scan_entity(entity, flush)
682 ENTITY *entity;
683 int flush;
684 {
685 #if REPORT_CHECK_SCAN_VERBOSE
686     if (debug & DEBUG_CFGEVAL_FLAG)
687         report(LOG_DEBUG, "check_value_scan_entity: " PF_ENTITY,
688                 PA_ENTITY(entity));
689 #endif
690
691     if (!flush && entity->value_scan.seq == value_scan_seq)
692         return;
693     check_request_scan_entity(entity, 0);
694
695     entity->value_scan.seen = 0;
696     entity->value_scan.from = NULL;
697     entity->value_scan.seq = value_scan_seq;
698
699     if (debug & DEBUG_CFGEVAL_FLAG)
700         report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
701                 PA_ENTITY(entity));
702 }
703
704 static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
705
706 static void
707 check_eval_scan_entity(entity, flush)
708 ENTITY *entity;
709 int flush;
710 {
711     struct tac_list_node *child_membership_parent_node;
712
713 #if REPORT_CHECK_SCAN_VERBOSE
714     if (debug & DEBUG_CFGEVAL_FLAG)
715         report(LOG_DEBUG, "check_eval_scan_entity: " PF_ENTITY,
716                 PA_ENTITY(entity));
717 #endif
718
719     if (!flush && entity->eval_scan.seq == eval_scan_seq)
720         return;         /* up to date */
721     check_value_scan_entity(entity, 0);
722
723     entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
724
725     if ((child_membership_parent_node = tac_list_first_node(&entity->to_child_membership_list))) {
726         struct membership *child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_parent_node);
727
728         entity->eval_scan.unsolved_to_child_membership_first = child_membership;
729     } else
730         entity->eval_scan.unsolved_to_child_membership_first = NULL;
731
732 #ifdef SCAN_PARANOIA
733     {
734         struct tac_list_node *notify_expr_node;
735
736         while ((notify_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
737             struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
738
739             if (notify_expr->u.entity.entity != entity)
740                 report(LOG_ERR, "INTERNAL: notify_expr->entity != entity");
741             if (notify_expr->eval_scan.seq != entity->eval_scan.seq)
742                 report(LOG_ERR, "INTERNAL: notify_expr seq != entity seq");
743             tac_list_node_remove(notify_expr_node);
744         }
745
746         if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
747             tac_list_node_remove(&entity->eval_scan.pending_entity_node);
748     }
749 #else /* SCAN_PARANOIA */
750     tac_list_init(&entity->eval_scan.notify_expr_list);
751     tac_list_node_init(&entity->eval_scan.pending_entity_node);
752 #endif /* SCAN_PARANOIA */
753
754     entity->eval_scan.seq = eval_scan_seq;      /* used above, keep as LAST! */
755
756     if (debug & DEBUG_CFGEVAL_FLAG)
757         report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
758                 PA_ENTITY(entity));
759 }
760
761
762 /* invalidation managing section (for '*_scan_begin()'):
763  */
764
765 /* this will happen once upon 'unsigned' overflow, ehm */
766
767 #define INVALIDATE_SEQ_PTR(object,ptr) \
768     (G_STRUCT_MEMBER(unsigned, ptr, invalidate_scan_##object##_table[what]) = (unsigned) -1)
769 #define INVALIDATE_SEQ(object) \
770     (INVALIDATE_SEQ_PTR(object,object))
771
772 static const long invalidate_scan_expr_table[IS_MAX]={
773     G_STRUCT_OFFSET(struct expr, request_scan.seq),
774     -1,
775     G_STRUCT_OFFSET(struct expr,    eval_scan.seq)};
776
777 static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
778
779 static void
780 invalidate_scan_expr(expr_single, what)
781 struct expr *expr_single;
782 enum invalidate_scan what;
783 {
784     struct expr *expr_parent, *expr_child;
785
786     if (!expr_single) {
787         report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
788         return;
789     }
790     if (expr_single->parent) {
791         report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
792         return;
793     }
794
795     /* TOP->DOWN scanner: */
796 top_down:
797     do {
798         INVALIDATE_SEQ_PTR(expr,expr_single);
799         expr_parent = expr_single;
800
801         switch (expr_parent->type) {
802
803         case S_not:
804             expr_child = expr_parent->u.not.child;
805             continue;
806
807         case S_and:
808         case S_or:
809             expr_child = expr_parent->u.and_or.child_first;
810             break;
811
812         case S_user:
813         case S_host:
814         case S_group:
815             expr_child = NULL;  /* no child exists */
816             break;
817
818         default:
819             report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
820             return;
821         }
822     } while ((expr_single = expr_child));
823     /* expr_child==NULL, we have only expr_parent: */
824
825     expr_child = expr_parent;
826
827     /* we have only expr_child: */
828     /* BOTTOM->UP scanner */
829     do {
830         if ((expr_single = expr_child->next))
831             goto top_down;
832         expr_parent = expr_child->parent;
833     } while ((expr_child = expr_parent));
834 }
835
836 static const long invalidate_scan_membership_table[IS_MAX]={
837     G_STRUCT_OFFSET(struct membership, request_scan.seq),
838     -1,
839     G_STRUCT_OFFSET(struct membership,    eval_scan.seq)};
840
841 static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
842
843 static void
844 invalidate_scan_membership(membership, what)
845 struct membership *membership;
846 enum invalidate_scan what;
847 {
848     INVALIDATE_SEQ(membership);
849
850     if (membership->when)
851         invalidate_scan_expr(membership->when, what);
852 }
853
854 static const long invalidate_scan_entity_table[IS_MAX]={
855     G_STRUCT_OFFSET(ENTITY, request_scan.seq),
856     G_STRUCT_OFFSET(ENTITY,   value_scan.seq),
857     G_STRUCT_OFFSET(ENTITY,    eval_scan.seq)};
858
859 static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
860
861 static void
862 invalidate_scan_entity(entity, what)
863 ENTITY *entity;
864 enum invalidate_scan what;
865 {
866     struct tac_list_node *child_membership_node;
867     struct membership *child_membership;
868
869     INVALIDATE_SEQ(entity);
870
871     if (what==IS_VALUE)         /* optimalization */
872         return;
873
874     for (
875             child_membership_node = tac_list_first_node(&entity->to_child_membership_list);
876             child_membership_node;
877             child_membership_node = tac_list_node_next(&child_membership->parent_node)
878             ) {
879         child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
880         invalidate_scan_membership(child_membership, what);
881     }
882 }
883
884 void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
885
886 void
887 scan_invalidate_entities_hashtable(hashtable, what)
888 void **hashtable;
889 enum invalidate_scan what;
890 {
891     int i;
892     ENTITY *entity;
893
894     for (i = 0; i < HASH_TAB_SIZE; i++)
895         for (entity = (ENTITY *) hashtable[i]; entity; entity = entity->hash)
896             invalidate_scan_entity(entity, what);
897 }
898
899 /* '*_scan_begin()' section:
900  */
901
902 void request_scan_begin TAC_ARGS((void));
903
904 void
905 request_scan_begin()
906 {
907 #ifdef SCAN_PARANOIA
908     static int inited = 0;
909 #endif /* SCAN_PARANOIA */
910
911     if (debug & DEBUG_CFGEVAL_FLAG)
912         report(LOG_DEBUG, "request_scan_begin:");
913
914     request_scan_user_known = 0;
915
916     if (!++request_scan_seq)
917         scan_invalidate_entities(IS_REQUEST);
918
919 #ifdef SCAN_PARANOIA
920     if (!inited) {
921 #endif /* SCAN_PARANOIA */
922         tac_list_init(&request_virtual_membership_list);
923 #ifdef SCAN_PARANOIA
924         inited = 1;
925     } else {
926         struct tac_list_node *virtual_membership_node;
927
928         while ((virtual_membership_node = tac_list_first_node(&request_virtual_membership_list))) {
929             struct membership *virtual_membership = VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node);
930
931             if (virtual_membership->request_scan.seq == request_scan_seq)
932                 report(LOG_ERR, "INTERNAL: request_virtual_membership_list membership seq == ++request_scan_seq in request_scan_begin");
933             tac_list_node_remove(virtual_membership_node);
934             unlink_membership(virtual_membership);
935             free_membership(virtual_membership);
936             }
937     }
938 #endif /* SCAN_PARANOIA */
939 }
940
941 static void value_scan_begin TAC_ARGS((ENTITY *entity));
942
943 static void
944 value_scan_begin(entity)
945 ENTITY *entity;
946 {
947     if (debug & DEBUG_CFGEVAL_FLAG)
948         report(LOG_DEBUG, "value_scan_begin:");
949
950     if (!++value_scan_seq)
951         scan_invalidate_entities(IS_VALUE);
952
953     check_value_scan_entity(entity, 0); /* sure as seq invalidated */
954     /* assumed (entity->value_scan.from == NULL) */
955 }
956
957 #ifdef SCAN_PARANOIA
958
959 static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
960
961 static void
962 eval_scan_begin_pending_entity_node(pending_entity_node)
963 struct tac_list_node *pending_entity_node;
964 {
965     ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
966
967     if (pending_entity->eval_scan.seq == eval_scan_seq)
968         report(LOG_ERR, "INTERNAL: eval_{pending}_entity_list entity seq == ++eval_scan_seq in eval_scan_begin");
969
970     tac_list_node_remove(pending_entity_node);
971 }
972
973 #endif /* SCAN_PARANOIA */
974
975 static void eval_scan_begin TAC_ARGS((void));
976
977 static void
978 eval_scan_begin()
979 {
980 #ifdef SCAN_PARANOIA
981     static int inited = 0;
982 #endif /* SCAN_PARANOIA */
983
984     if (debug & DEBUG_CFGEVAL_FLAG)
985         report(LOG_DEBUG, "eval_scan_begin:");
986
987     if (!++eval_scan_seq)
988         scan_invalidate_entities(IS_EVAL);
989
990 #ifdef SCAN_PARANOIA
991     if (!inited) {
992 #endif /* SCAN_PARANOIA */
993         tac_list_init(&eval_kicked_entity_list);
994         tac_list_init(&eval_destroy_entity_list);
995         tac_list_init(&eval_notified_expr_list);
996 #ifdef SCAN_PARANOIA
997         inited = 1;
998     } else {
999         struct tac_list_node *pending_entity_node;
1000         struct tac_list_node *notify_expr_node;
1001
1002         while ((pending_entity_node = tac_list_first_node(&eval_kicked_entity_list)))
1003             eval_scan_begin_pending_entity_node(pending_entity_node);
1004         while ((pending_entity_node = tac_list_first_node(&eval_destroy_entity_list)))
1005             eval_scan_begin_pending_entity_node(pending_entity_node);
1006
1007         while ((notify_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1008             struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
1009
1010             if (notify_expr->eval_scan.seq == eval_scan_seq)
1011                 report(LOG_ERR, "INTERNAL: eval_notified_expr_list expr seq == ++eval_scan_seq in eval_scan_begin");
1012
1013             tac_list_node_remove(notify_expr_node);
1014         }
1015     }
1016 #endif /* SCAN_PARANOIA */
1017 }
1018
1019 /* 'priority=0' => addtail - used for WANTED entities
1020  * 'priority=1' => addhead - used for SOLVED entities
1021  *                 It may be better to do insert it AFTER all currently solved
1022  *                 entities but may be not but who cares...
1023  */
1024
1025 static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
1026
1027 static void register_kicked_entity(entity, priority)
1028 ENTITY *entity;
1029 int priority;
1030 {
1031     struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1032
1033     check_eval_scan_entity(entity, 0);
1034
1035     if (tac_list_node_get_list(pending_entity_node) == &eval_destroy_entity_list) {
1036         tac_list_node_remove (pending_entity_node);
1037         if (debug & DEBUG_CFGEVAL_FLAG)
1038             report(LOG_DEBUG, "register_kicked_entity: REMOVED " PF_ENTITY " from eval_DESTROY_entity_list",
1039                     PA_ENTITY(entity));
1040     }
1041     if (tac_list_node_get_list(pending_entity_node) == NULL) {
1042         if (priority)
1043             tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
1044         else
1045             tac_list_addtail(&eval_kicked_entity_list, pending_entity_node);
1046         if (debug & DEBUG_CFGEVAL_FLAG)
1047             report(LOG_DEBUG, "register_kicked_entity: REGISTERED " PF_ENTITY " to eval_KICKED_entity_list (priority=%s)",
1048                     PA_ENTITY(entity), (priority ? "YES" : "NO"));
1049     }
1050 #ifdef SCAN_PARANOIA
1051     if ((tac_list_node_get_list(pending_entity_node) != &eval_kicked_entity_list)) {
1052         report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1053         return;
1054     }
1055 #endif
1056 }
1057
1058 /* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
1059
1060 static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
1061
1062 static void
1063 expr_eval_notify_expr(expr)
1064 struct expr *expr;
1065 {
1066     ENTITY *entity = expr->u.entity.entity;
1067
1068     if (debug & DEBUG_CFGEVAL_FLAG)
1069         report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED notify " PF_EXPR " when " PF_ENTITY " is known",
1070                 PA_EXPR(expr), PA_ENTITY(entity));
1071
1072     if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
1073 #ifdef SCAN_PARANOIA
1074         if (&entity->eval_scan.notify_expr_list
1075          != tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1076             report(LOG_ERR, "Another " PF_ENTITY " already registered in notify node of " PF_EXPR,
1077                 PA_ENTITY(EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr)), PA_EXPR(expr));
1078 #endif
1079         return;
1080     }
1081
1082     tac_list_addtail(&entity->eval_scan.notify_expr_list,
1083             &expr->eval_scan.u.entity.notify_expr_node);
1084
1085     register_kicked_entity(entity, 0 /* priority */);
1086 }
1087
1088 /* check_eval_scan_*() is assumed for "expr" ! */
1089
1090 static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
1091
1092 static void
1093 expr_eval_notify_expr_remove_internal(expr)
1094 struct expr *expr;
1095 {
1096     if (debug & DEBUG_CFGEVAL_FLAG)
1097         report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
1098                 PA_EXPR(expr));
1099
1100     if (!expr)
1101         return;
1102     if (expr->eval_scan.seq != eval_scan_seq)
1103         return;
1104     if (expr->request_scan.result != ER_UNKNOWN)
1105         return;
1106
1107     switch (expr->type) {
1108
1109     case S_not:
1110         expr_eval_notify_expr_remove_internal(expr->u.not.child);
1111         break;
1112
1113     case S_and:
1114     case S_or: {
1115         struct expr *child;
1116
1117         for (child=expr->u.and_or.child_first; child; child=child->next)
1118             expr_eval_notify_expr_remove_internal(child);
1119         } break;
1120
1121     case S_user:
1122     case S_host:
1123     case S_group: {
1124         ENTITY *entity = expr->u.entity.entity;
1125         struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1126
1127         if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1128             break;
1129
1130         tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
1131         if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
1132             break;
1133         /* no one is further interested in "entity" */
1134
1135         if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
1136             tac_list_node_remove (pending_entity_node);
1137             if (debug & DEBUG_CFGEVAL_FLAG)
1138                 report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
1139                         PA_ENTITY(entity));
1140         }
1141         if (tac_list_node_get_list(pending_entity_node) == NULL) {
1142             tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
1143             if (debug & DEBUG_CFGEVAL_FLAG)
1144                 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
1145                         PA_ENTITY(entity));
1146         }
1147 #ifdef SCAN_PARANOIA
1148         if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
1149             report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1150             return;
1151         }
1152 #endif
1153
1154         } break;
1155
1156     default:
1157         report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
1158         return;
1159     }
1160 }
1161
1162 static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
1163
1164 static void expr_eval_notify_expr_flush_destroy_entity_list()
1165 {
1166 struct tac_list_node *destroy_entity_node;
1167
1168     while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
1169         ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
1170         struct tac_list_node *destroy_notify_expr_node;
1171
1172         if (debug & DEBUG_CFGEVAL_FLAG)
1173             report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
1174                     PA_ENTITY(destroy_entity));
1175
1176         while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
1177             struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
1178
1179             expr_eval_notify_expr_remove_internal(destroy_notify_expr);
1180         }
1181     }
1182 }
1183
1184 static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
1185
1186 static void
1187 expr_eval_notify_expr_remove(expr)
1188 struct expr *expr;
1189 {
1190     if (debug & DEBUG_CFGEVAL_FLAG)
1191         report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
1192                 PA_EXPR(expr));
1193
1194     expr_eval_notify_expr_remove_internal(expr);
1195     expr_eval_notify_expr_flush_destroy_entity_list();
1196 }
1197
1198 /* It would be very nice to try to optimize the expression before evaluation.
1199
1200    We are not interested in some CPU time complexity of the expression.
1201    But we would be very happy to discard any user/host/group membership
1202    dependencies (our 'variables'). Unfortunately such optimization is
1203    NP problem (classification by courtesy of Daniel Kral) so it is considered
1204    too expensive for us.
1205
1206    TODO in future: Full NP optimization for small number of variables and/or
1207    heuristic optimizations for complex expressions.
1208 */
1209
1210 static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
1211
1212 static enum eval_result
1213 expr_eval_immediate(expr_single)
1214 struct expr *expr_single;
1215 {
1216     struct expr *expr_child, *expr_parent;
1217     enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
1218
1219     if (debug & DEBUG_CFGEVAL_FLAG)
1220         report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
1221                 PA_EXPR(expr_single));
1222
1223     if (!expr_single)
1224         return (ER_TRUE);
1225
1226     /* TOP->DOWN scanner: */
1227 top_down:
1228     while (1) {
1229         enum eval_result result_single;
1230
1231         if (debug & DEBUG_CFGEVAL_FLAG)
1232             report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
1233                     PA_EXPR(expr_single));
1234
1235         check_eval_scan_expr(expr_single, 0);
1236         result_single = expr_single->request_scan.result;
1237         if (result_single != ER_UNKNOWN)
1238             break;
1239         switch (expr_single->type) {
1240
1241         case S_not:
1242             expr_single = expr_single->u.not.child;
1243             continue;
1244
1245         case S_and:
1246         case S_or:
1247             expr_single = expr_single->u.and_or.child_first;
1248             continue;
1249
1250         case S_user:
1251         case S_host:
1252         case S_group: {
1253             ENTITY *entity = expr_single->u.entity.entity;
1254
1255             check_eval_scan_entity(entity, 0);
1256
1257             if (entity->request_scan.belongs == ER_UNKNOWN)
1258                 expr_eval_notify_expr(expr_single);
1259             else
1260                 result_single = entity->request_scan.belongs;
1261             } break;
1262
1263         default:
1264             report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
1265             return (ER_UNKNOWN);
1266         }
1267
1268         expr_single->request_scan.result = result_single;
1269         break;
1270     }
1271
1272     /* BOTTOM->UP scanner: */
1273     do {
1274         if (debug & DEBUG_CFGEVAL_FLAG)
1275             report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
1276                     PA_EXPR(expr_single));
1277
1278         expr_parent = expr_single->parent;
1279         if (!expr_parent)
1280             break;
1281         if (expr_parent->eval_scan.seq != eval_scan_seq) {
1282             report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
1283             return (ER_UNKNOWN);
1284         }
1285         if (expr_parent->request_scan.seq != request_scan_seq) {
1286             report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
1287             return (ER_UNKNOWN);
1288         }
1289         if (expr_parent->request_scan.result != ER_UNKNOWN) {
1290             report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
1291             return (ER_UNKNOWN);
1292         }
1293
1294         expr_child = expr_single;
1295         result_child = expr_child->request_scan.result;
1296
1297         if (debug & DEBUG_CFGEVAL_FLAG)
1298             report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
1299                     PA_EXPR(expr_child), PA_EXPR(expr_parent));
1300
1301         switch (expr_parent->type) {
1302
1303         case S_not:
1304             switch (result_child) {
1305             case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
1306             case ER_FALSE:   result_parent = ER_TRUE;    break;
1307             case ER_TRUE:    result_parent = ER_FALSE;   break;
1308             }
1309             break;
1310
1311         case S_and:
1312         case S_or: {
1313             enum eval_result veto    = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
1314             enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE  : ER_FALSE);
1315
1316                  if (result_child == veto)
1317                 result_parent = veto;
1318             else if (result_child == ER_UNKNOWN || result_child == consent) {
1319                 if (expr_child->next) {
1320                     expr_single = expr_child->next;
1321                     if (debug & DEBUG_CFGEVAL_FLAG)
1322                         report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
1323                                 PA_EXPR(expr_single));
1324                     goto top_down;
1325                 }
1326
1327                 if (debug & DEBUG_CFGEVAL_FLAG)
1328                     report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
1329                             PA_EXPR(expr_single));
1330
1331                 /* It would be nice to pretend that all 'veto' decisions already made in the child
1332                  * had to set our 'result' to the correct value. But 'consent' decisions don't set
1333                  * us and the behaviour of auto-set from the child in 'veto' case may get changed
1334                  * in the future versions.
1335                  * So we rather don't depend on it.
1336                  * This overhead doesn't change altgorithmic complexity anyway.
1337                  */
1338                 result_parent = consent;
1339                 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1340                 {
1341                     check_eval_scan_expr(expr_child, 0);        /* shouldn't be needed */
1342                          if (expr_child->request_scan.result == ER_UNKNOWN)
1343                         result_parent = ER_UNKNOWN;     /* assumed (result_parent != veto) */
1344                     else if (expr_child->request_scan.result == veto) {
1345                         result_parent = veto;
1346                         break;
1347                     }
1348                 }
1349                 break;
1350             }
1351             } break;
1352
1353         default:
1354             report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1355             return (ER_UNKNOWN);
1356         }
1357
1358         if (debug & DEBUG_CFGEVAL_FLAG)
1359             report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1360                     PA_EXPR(expr_child), PA_EXPR(expr_parent));
1361
1362         if (result_parent != ER_UNKNOWN) {
1363             expr_parent->request_scan.result = result_parent;
1364             /* we no longer need any notifications from entities to solve sub-expression */
1365             expr_eval_notify_expr_remove(expr_parent);
1366         }
1367
1368         expr_single = expr_parent;
1369     } while (0);
1370     /* The whole expression has been scanned to its root, we have "expr_single" */
1371
1372     if (debug & DEBUG_CFGEVAL_FLAG)
1373         report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1374                 PA_EXPR(expr_single));
1375
1376     return (expr_single->request_scan.result);
1377 }
1378
1379 static void membership_solved TAC_ARGS((struct membership *membership));
1380
1381 static void
1382 membership_solved(membership)
1383 struct membership *membership;
1384 {
1385     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1386
1387     check_request_scan_entity(parent_entity, 0);
1388
1389 #ifdef SCAN_PARANOIA
1390     if (!membership->eval_scan.unsolved) {
1391         report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1392         return;
1393     }
1394 #endif
1395
1396     membership->eval_scan.unsolved = 0;
1397
1398 #ifdef SCAN_PARANOIA
1399     if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1400         report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1401         parent_entity->eval_scan.unsolved_to_child_membership_num++;
1402     }
1403 #endif
1404     parent_entity->eval_scan.unsolved_to_child_membership_num--;
1405
1406     if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1407      && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1408         parent_entity->request_scan.belongs = ER_FALSE;
1409         register_kicked_entity(parent_entity, 1 /* priority */);
1410     }
1411 }
1412
1413 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1414
1415 static void
1416 membership_parent_solve(membership, how)
1417 struct membership *membership;
1418 enum eval_result how;
1419 {
1420     enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1421     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1422
1423     check_request_scan_entity(parent_entity, 0);
1424
1425     if (parent_entity->request_scan.belongs == negative)
1426         report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1427                 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1428
1429     parent_entity->request_scan.belongs = how;
1430     register_kicked_entity(parent_entity, 1 /* priority */);
1431
1432     membership_solved(membership);
1433
1434     if (debug & DEBUG_CFGEVAL_FLAG)
1435         report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1436                 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1437 }
1438
1439 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1440
1441 static void
1442 membership_eval_immediate(membership)
1443 struct membership *membership;
1444 {
1445     enum eval_result membership_valid;
1446     ENTITY *child_entity, *parent_entity;
1447
1448     if (debug & DEBUG_CFGEVAL_FLAG)
1449         report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1450                 PA_MEMBERSHIP(membership));
1451
1452     check_eval_scan_membership(membership, 0);
1453
1454     if (!membership->eval_scan.unsolved)
1455         return;
1456     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1457     check_request_scan_entity(parent_entity, 0);
1458     if (parent_entity->request_scan.belongs != ER_UNKNOWN)      /* why to solve this membership? */
1459         return;
1460
1461     membership_valid = expr_eval_immediate(membership->when);
1462
1463     child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1464     check_request_scan_entity( child_entity, 0);
1465
1466 #if 0 /* non-valid membership doesn't YET solve the parent! */
1467     if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1468         membership_parent_solve(membership, ER_FALSE);
1469         return;
1470     }
1471 #endif
1472
1473     if (child_entity->request_scan.belongs == ER_TRUE  && membership_valid == ER_TRUE ) {
1474         membership_parent_solve(membership, ER_TRUE );
1475         return;
1476     }
1477
1478     if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1479         register_kicked_entity( child_entity, 0 /* priority */);
1480     if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1481         register_kicked_entity(parent_entity, 0 /* priority */);
1482
1483     if (parent_entity->request_scan.belongs != ER_UNKNOWN
1484      || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1485         membership_solved(membership);
1486
1487     if (debug & DEBUG_CFGEVAL_FLAG)
1488         report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1489                 PA_MEMBERSHIP(membership));
1490 }
1491
1492 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1493
1494 static void
1495 entity_eval_immediate(entity)
1496 ENTITY *entity;
1497 {
1498     struct tac_list_node *notified_expr_node;
1499     struct tac_list_node *child_membership_node;
1500
1501     if (debug & DEBUG_CFGEVAL_FLAG)
1502         report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1503                 PA_ENTITY(entity));
1504
1505     check_eval_scan_entity(entity, 0);
1506
1507     if (!request_scan_user_known) {
1508 #ifdef SCAN_PARANOIA
1509         if (entity->request_scan.belongs != ER_UNKNOWN)
1510             report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1511                     PA_ENTITY(entity));
1512 #endif
1513         return;
1514     }
1515
1516     if (entity->request_scan.belongs == ER_UNKNOWN) {
1517         if (entity->eval_scan.unsolved_to_child_membership_first) {
1518             struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1519             struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1520
1521             membership_eval_immediate(order_membership);
1522             if (next_membership_parent_node)
1523                 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1524             else
1525                 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1526
1527             register_kicked_entity(entity, 0 /* priority */);
1528
1529             if (debug & DEBUG_CFGEVAL_FLAG)
1530                 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1531                         PA_MEMBERSHIP(order_membership));
1532             return;
1533         }
1534
1535         if (!entity->eval_scan.unsolved_to_child_membership_num)
1536             entity->request_scan.belongs = ER_FALSE;
1537         else {
1538             if (debug & DEBUG_CFGEVAL_FLAG)
1539                 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1540             return;
1541         }
1542     }
1543     /* belonging is known here */
1544
1545     /* recheck all memberships we may decide */
1546     for (
1547             child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1548             child_membership_node;
1549             child_membership_node = tac_list_node_next(child_membership_node)
1550             ) {
1551         struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1552
1553         membership_eval_immediate(child_membership);
1554     }
1555
1556     /* notify all exprs which are interested in us */
1557     while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1558         tac_list_node_remove(notified_expr_node);
1559         tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1560     }
1561
1562     if (debug & DEBUG_CFGEVAL_FLAG)
1563         report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1564                 PA_ENTITY(entity));
1565 }
1566
1567
1568 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1569
1570 enum eval_result
1571 expr_eval(expr)
1572 struct expr *expr;
1573 {
1574     if (debug & DEBUG_CFGEVAL_FLAG)
1575         report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1576                 PA_EXPR(expr));
1577
1578     if (!expr)
1579         return (ER_TRUE);
1580
1581     eval_scan_begin();
1582     if (expr_eval_immediate(expr) != ER_UNKNOWN)
1583         return (expr->request_scan.result);
1584
1585     /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1586      * otherwise we may have no longer valid node!
1587      */
1588     for (;;) {
1589         struct tac_list_node *notified_expr_node, *kicked_entity_node;
1590
1591         /* check it rather always, checking just on notifications looks too complex.
1592         */
1593         if (expr->request_scan.result != ER_UNKNOWN) {
1594             if (debug & DEBUG_CFGEVAL_FLAG)
1595                 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1596                         PA_EXPR(expr));
1597             return (expr->request_scan.result);
1598         }
1599
1600 #if 0   /* not needed as it is now always called after any destroy */
1601         expr_eval_notify_expr_flush_destroy_entity_list();      /* eval_destroy_entity_list */
1602 #endif  /* not needed */
1603
1604         if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1605             struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1606
1607             if (debug & DEBUG_CFGEVAL_FLAG)
1608                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1609                         PA_EXPR(notified_expr));
1610
1611             tac_list_node_remove(notified_expr_node);
1612             expr_eval_immediate(notified_expr);
1613
1614             if (notified_expr->membership)
1615                 membership_eval_immediate(notified_expr->membership);
1616
1617             continue;           /* shortcut */
1618         }
1619
1620         if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1621             ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1622
1623             if (debug & DEBUG_CFGEVAL_FLAG)
1624                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1625                         PA_ENTITY(kicked_entity));
1626
1627             tac_list_node_remove(kicked_entity_node);
1628             entity_eval_immediate(kicked_entity);
1629             continue;           /* shortcut */
1630         }
1631
1632         break;  /* nothing done yet, all lists are empty! */
1633     }
1634
1635     if (!expr->request_scan.loop_reported) {
1636         report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1637         expr->request_scan.loop_reported = 1;
1638     }
1639     return (ER_UNKNOWN);
1640 }
1641
1642
1643 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1644
1645 void eval_force_belong_entity(entity)
1646 ENTITY *entity;
1647 {
1648     if (debug & DEBUG_CFGEVAL_FLAG)
1649         report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1650                 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1651
1652     check_request_scan_entity(entity, 0);
1653
1654     if (entity->request_scan.belongs == ER_FALSE)
1655         report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1656
1657     entity->request_scan.belongs = ER_TRUE;
1658 }
1659
1660 void scan_init_entity TAC_ARGS((ENTITY *entity));
1661
1662 void
1663 scan_init_entity(entity)
1664 ENTITY *entity;
1665 {
1666     entity->request_scan.seq = request_scan_seq-1;      /* invalidate */
1667     entity->  value_scan.seq =   value_scan_seq-1;      /* invalidate */
1668     entity->   eval_scan.seq =    eval_scan_seq-1;      /* invalidate */
1669     tac_list_init(&entity->eval_scan.notify_expr_list);
1670     tac_list_node_init(&entity->eval_scan.pending_entity_node);
1671 }
1672
1673 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1674
1675 struct membership *
1676 enlist_entity_direct(parent, child, when)
1677 ENTITY *parent;
1678 ENTITY *child;
1679 struct expr *when;
1680 {
1681     struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1682
1683     tac_list_node_init(&membership->parent_node);
1684     tac_list_node_init(&membership->child_node);
1685     membership->request_scan.seq = request_scan_seq-1;
1686     tac_list_node_init(&membership->request_scan.virtual_membership_node);
1687     membership->eval_scan.seq = eval_scan_seq-1;
1688
1689     tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1690     parent->to_child_membership_num++;
1691     tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1692     membership->when = when;
1693     if (expr_sink(membership->when, membership)) {
1694         unlink_membership(membership);
1695         free_membership(membership);
1696         return (NULL);
1697     }
1698
1699     if (debug & DEBUG_CFGEVAL_FLAG)
1700         report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1701                 PA_MEMBERSHIP(membership));
1702
1703     return (membership);
1704 }
1705
1706 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1707
1708 struct membership *
1709 virtual_enlist_entity_direct(parent, child)
1710 ENTITY *parent;
1711 ENTITY *child;
1712 {
1713     struct membership *membership;
1714
1715     if (debug & DEBUG_CFGEVAL_FLAG)
1716         report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1717
1718     membership = enlist_entity_direct(parent, child, NULL /* when */);
1719     if (!membership)
1720         return (NULL);
1721
1722     check_request_scan_membership(membership, 0);
1723     tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1724
1725     return (membership);
1726 }
1727
1728 /* returns given 'entity' or NULL if already visited */
1729
1730 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1731
1732 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1733
1734 static ENTITY *
1735 value_scan_forward(membership)
1736 struct membership *membership;
1737 {
1738     ENTITY *parent_entity;
1739
1740     if (debug & DEBUG_CFGEVAL_FLAG)
1741         report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1742                 PA_MEMBERSHIP(membership));
1743
1744     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1745
1746     if (ER_TRUE != expr_eval(membership->when)) {
1747         if (debug & DEBUG_CFGEVAL_FLAG)
1748             report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1749         return (NULL);
1750     }
1751     check_value_scan_entity(parent_entity, 0);
1752     if (parent_entity->value_scan.seen) {
1753         if (debug & DEBUG_CFGEVAL_FLAG)
1754             report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1755                     PA_ENTITY(parent_entity));
1756         if (value_scan_forward_seen_hook)
1757             (*value_scan_forward_seen_hook)(membership);
1758         return (NULL);
1759     }
1760     parent_entity->value_scan.seen = 1;
1761     parent_entity->value_scan.from = membership;
1762
1763     if (debug & DEBUG_CFGEVAL_FLAG)
1764         report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1765                 PA_ENTITY(parent_entity));
1766     return (parent_entity);
1767 }
1768
1769 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1770
1771 struct membership *
1772 value_scan_backward(entity)
1773 ENTITY *entity;
1774 {
1775     if (debug & DEBUG_CFGEVAL_FLAG)
1776         report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1777                 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1778
1779 #ifdef SCAN_PARANOIA
1780     if (entity->value_scan.seq != value_scan_seq) {
1781         report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1782         return (NULL);
1783     }
1784 #endif
1785
1786     return (entity->value_scan.from);
1787 }
1788
1789 /* Scan the entity graph and return each node found.
1790    'when' conditions for graph connections are respected,
1791    looping is correctly prevented.
1792 */
1793
1794 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1795
1796 enum value_scan_func_result
1797 value_scan_entity(entity, recurse, func, func_data)
1798 ENTITY *entity;
1799 int recurse;
1800 value_scan_func_t func;
1801 void *func_data;
1802 {
1803     enum value_scan_func_result vsfr;
1804     struct tac_list_node *membership_node;
1805
1806     if (debug & DEBUG_CFGEVAL_FLAG)
1807         report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1808                 PA_ENTITY(entity), recurse);
1809
1810     vsfr=(*func)(entity,func_data);
1811
1812     if (debug & DEBUG_CFGEVAL_FLAG)
1813         report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1814                 PA_VSFR(vsfr));
1815
1816     if (vsfr != VSFR_CONTINUE) {
1817         if (debug & DEBUG_CFGEVAL_FLAG)
1818             report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1819         return (vsfr);
1820     }
1821     if (!recurse ) {
1822         if (debug & DEBUG_CFGEVAL_FLAG)
1823             report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1824         return (VSFR_STOP);
1825     }
1826
1827     value_scan_begin(entity);
1828     membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1829     if (!membership_node) {
1830         if (debug & DEBUG_CFGEVAL_FLAG)
1831             report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1832         return (VSFR_CONTINUE);         /* no parent entities */
1833     }
1834
1835     while (1) {
1836         struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1837
1838         if (debug & DEBUG_CFGEVAL_FLAG)
1839             report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1840                     PA_MEMBERSHIP(membership));
1841
1842         entity = value_scan_forward(membership);
1843         if (entity) {
1844             if (debug & DEBUG_CFGEVAL_FLAG)
1845                 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1846                         PA_ENTITY(entity));
1847
1848             vsfr=(*func)(entity,func_data);
1849
1850             if (debug & DEBUG_CFGEVAL_FLAG)
1851                 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1852                         PA_ENTITY(entity), PA_VSFR(vsfr));
1853
1854             if (vsfr == VSFR_FOUND) {
1855                 if (debug & DEBUG_CFGEVAL_FLAG)
1856                     report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1857                 return (vsfr);
1858             }
1859             if (vsfr == VSFR_CONTINUE)
1860                 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1861         }
1862         if (!entity || vsfr == VSFR_STOP) {
1863             ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1864
1865             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1866
1867             if (debug & DEBUG_CFGEVAL_FLAG)
1868                 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1869                         PA_ENTITY(parent_entity), PA_ENTITY(entity));
1870
1871             membership_node = tac_list_node_next(&membership->child_node);
1872         }
1873
1874         while (!membership_node) {
1875             membership = value_scan_backward(entity);
1876             if (!membership) {
1877                 if (debug & DEBUG_CFGEVAL_FLAG)
1878                     report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1879                 return (VSFR_CONTINUE);         /* FINISH */
1880             }
1881
1882             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1883
1884             if (debug & DEBUG_CFGEVAL_FLAG)
1885                 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1886                                 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1887                                 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1888
1889             membership_node = tac_list_node_next(&membership->child_node);
1890         }
1891     }
1892     /* NOTREACHED */
1893 }