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