54357097845eed7bc3a4a6716a1d23e29510e87c
[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                 /* It would be nice to pretend that all 'veto' decisions already made in the child
1330                  * had to set our 'result' to the correct value. But 'consent' decisions don't set
1331                  * us and the behaviour of auto-set from the child in 'veto' case may get changed
1332                  * in the future versions.
1333                  * So we rather don't depend on it.
1334                  * This overhead doesn't change altgorithmic complexity anyway.
1335                  */
1336                 result_parent = consent;
1337                 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1338                 {
1339                     check_eval_scan_expr(expr_child, 0);        /* shouldn't be needed */
1340                          if (expr_child->request_scan.result == ER_UNKNOWN)
1341                         result_parent = ER_UNKNOWN;     /* assumed (result_parent != veto) */
1342                     else if (expr_child->request_scan.result == veto) {
1343                         result_parent = veto;
1344                         break;
1345                     }
1346                 }
1347                 break;
1348             }
1349             } break;
1350
1351         default:
1352             report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1353             return (ER_UNKNOWN);
1354         }
1355
1356         if (debug & DEBUG_CFGEVAL_FLAG)
1357             report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1358                     PA_EXPR(expr_child), PA_EXPR(expr_parent));
1359
1360         if (result_parent != ER_UNKNOWN) {
1361             expr_parent->request_scan.result = result_parent;
1362             /* we no longer need any notifications from entities to solve sub-expression */
1363             expr_eval_notify_expr_remove(expr_parent);
1364         }
1365
1366         expr_single = expr_parent;
1367     } while (0);
1368     /* The whole expression has been scanned to its root, we have "expr_single" */
1369
1370     if (debug & DEBUG_CFGEVAL_FLAG)
1371         report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1372                 PA_EXPR(expr_single));
1373
1374     return (expr_single->request_scan.result);
1375 }
1376
1377 static void membership_solved TAC_ARGS((struct membership *membership));
1378
1379 static void
1380 membership_solved(membership)
1381 struct membership *membership;
1382 {
1383     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1384
1385     check_request_scan_entity(parent_entity, 0);
1386
1387 #ifdef SCAN_PARANOIA
1388     if (!membership->eval_scan.unsolved) {
1389         report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1390         return;
1391     }
1392 #endif
1393
1394     membership->eval_scan.unsolved = 0;
1395
1396 #ifdef SCAN_PARANOIA
1397     if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1398         report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1399         parent_entity->eval_scan.unsolved_to_child_membership_num++;
1400     }
1401 #endif
1402     parent_entity->eval_scan.unsolved_to_child_membership_num--;
1403
1404     if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1405      && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1406         parent_entity->request_scan.belongs = ER_FALSE;
1407         register_kicked_entity(parent_entity, 1 /* priority */);
1408     }
1409 }
1410
1411 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1412
1413 static void
1414 membership_parent_solve(membership, how)
1415 struct membership *membership;
1416 enum eval_result how;
1417 {
1418     enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1419     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1420
1421     check_request_scan_entity(parent_entity, 0);
1422
1423     if (parent_entity->request_scan.belongs == negative)
1424         report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1425                 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1426
1427     parent_entity->request_scan.belongs = how;
1428     register_kicked_entity(parent_entity, 1 /* priority */);
1429
1430     membership_solved(membership);
1431
1432     if (debug & DEBUG_CFGEVAL_FLAG)
1433         report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1434                 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1435 }
1436
1437 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1438
1439 static void
1440 membership_eval_immediate(membership)
1441 struct membership *membership;
1442 {
1443     enum eval_result membership_valid;
1444     ENTITY *child_entity, *parent_entity;
1445
1446     if (debug & DEBUG_CFGEVAL_FLAG)
1447         report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1448                 PA_MEMBERSHIP(membership));
1449
1450     check_eval_scan_membership(membership, 0);
1451
1452     if (!membership->eval_scan.unsolved)
1453         return;
1454     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1455     check_request_scan_entity(parent_entity, 0);
1456     if (parent_entity->request_scan.belongs != ER_UNKNOWN)      /* why to solve this membership? */
1457         return;
1458
1459     membership_valid = expr_eval_immediate(membership->when);
1460
1461     child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1462     check_request_scan_entity( child_entity, 0);
1463
1464 #if 0 /* non-valid membership doesn't YET solve the parent! */
1465     if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1466         membership_parent_solve(membership, ER_FALSE);
1467         return;
1468     }
1469 #endif
1470
1471     if (child_entity->request_scan.belongs == ER_TRUE  && membership_valid == ER_TRUE ) {
1472         membership_parent_solve(membership, ER_TRUE );
1473         return;
1474     }
1475
1476     if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1477         register_kicked_entity( child_entity, 0 /* priority */);
1478     if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1479         register_kicked_entity(parent_entity, 0 /* priority */);
1480
1481     if (parent_entity->request_scan.belongs != ER_UNKNOWN
1482      || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1483         membership_solved(membership);
1484
1485     if (debug & DEBUG_CFGEVAL_FLAG)
1486         report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1487                 PA_MEMBERSHIP(membership));
1488 }
1489
1490 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1491
1492 static void
1493 entity_eval_immediate(entity)
1494 ENTITY *entity;
1495 {
1496     struct tac_list_node *notified_expr_node;
1497     struct tac_list_node *child_membership_node;
1498
1499     if (debug & DEBUG_CFGEVAL_FLAG)
1500         report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1501                 PA_ENTITY(entity));
1502
1503     check_eval_scan_entity(entity, 0);
1504
1505     if (!request_scan_user_known) {
1506 #ifdef SCAN_PARANOIA
1507         if (entity->request_scan.belongs != ER_UNKNOWN)
1508             report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1509                     PA_ENTITY(entity));
1510 #endif
1511         return;
1512     }
1513
1514     if (entity->request_scan.belongs == ER_UNKNOWN) {
1515         if (entity->eval_scan.unsolved_to_child_membership_first) {
1516             struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1517             struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1518
1519             membership_eval_immediate(order_membership);
1520             if (next_membership_parent_node)
1521                 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1522             else
1523                 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1524
1525             register_kicked_entity(entity, 0 /* priority */);
1526
1527             if (debug & DEBUG_CFGEVAL_FLAG)
1528                 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1529                         PA_MEMBERSHIP(order_membership));
1530             return;
1531         }
1532
1533         if (!entity->eval_scan.unsolved_to_child_membership_num)
1534             entity->request_scan.belongs = ER_FALSE;
1535         else {
1536             if (debug & DEBUG_CFGEVAL_FLAG)
1537                 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1538             return;
1539         }
1540     }
1541     /* belonging is known here */
1542
1543     /* recheck all memberships we may decide */
1544     for (
1545             child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1546             child_membership_node;
1547             child_membership_node = tac_list_node_next(child_membership_node)
1548             ) {
1549         struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1550
1551         membership_eval_immediate(child_membership);
1552     }
1553
1554     /* notify all exprs which are interested in us */
1555     while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1556         tac_list_node_remove(notified_expr_node);
1557         tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1558     }
1559
1560     if (debug & DEBUG_CFGEVAL_FLAG)
1561         report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1562                 PA_ENTITY(entity));
1563 }
1564
1565
1566 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1567
1568 enum eval_result
1569 expr_eval(expr)
1570 struct expr *expr;
1571 {
1572     if (debug & DEBUG_CFGEVAL_FLAG)
1573         report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1574                 PA_EXPR(expr));
1575
1576     if (!expr)
1577         return (ER_TRUE);
1578
1579     eval_scan_begin();
1580     if (expr_eval_immediate(expr) != ER_UNKNOWN)
1581         return (expr->request_scan.result);
1582
1583     /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1584      * otherwise we may have no longer valid node!
1585      */
1586     for (;;) {
1587         struct tac_list_node *notified_expr_node, *kicked_entity_node;
1588
1589         /* check it rather always, checking just on notifications looks too complex.
1590         */
1591         if (expr->request_scan.result != ER_UNKNOWN) {
1592             if (debug & DEBUG_CFGEVAL_FLAG)
1593                 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1594                         PA_EXPR(expr));
1595             return (expr->request_scan.result);
1596         }
1597
1598 #if 0   /* not needed as it is now always called after any destroy */
1599         expr_eval_notify_expr_flush_destroy_entity_list();      /* eval_destroy_entity_list */
1600 #endif  /* not needed */
1601
1602         if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1603             struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1604
1605             if (debug & DEBUG_CFGEVAL_FLAG)
1606                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1607                         PA_EXPR(notified_expr));
1608
1609             tac_list_node_remove(notified_expr_node);
1610             expr_eval_immediate(notified_expr);
1611
1612             if (notified_expr->membership)
1613                 membership_eval_immediate(notified_expr->membership);
1614
1615             continue;           /* shortcut */
1616         }
1617
1618         if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1619             ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1620
1621             if (debug & DEBUG_CFGEVAL_FLAG)
1622                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1623                         PA_ENTITY(kicked_entity));
1624
1625             tac_list_node_remove(kicked_entity_node);
1626             entity_eval_immediate(kicked_entity);
1627             continue;           /* shortcut */
1628         }
1629
1630         break;  /* nothing done yet, all lists are empty! */
1631     }
1632
1633     if (!expr->request_scan.loop_reported) {
1634         report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1635         expr->request_scan.loop_reported = 1;
1636     }
1637     return (ER_UNKNOWN);
1638 }
1639
1640
1641 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1642
1643 void eval_force_belong_entity(entity)
1644 ENTITY *entity;
1645 {
1646     if (debug & DEBUG_CFGEVAL_FLAG)
1647         report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1648                 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1649
1650     check_request_scan_entity(entity, 0);
1651
1652     if (entity->request_scan.belongs == ER_FALSE)
1653         report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1654
1655     entity->request_scan.belongs = ER_TRUE;
1656 }
1657
1658 void scan_init_entity TAC_ARGS((ENTITY *entity));
1659
1660 void
1661 scan_init_entity(entity)
1662 ENTITY *entity;
1663 {
1664     entity->request_scan.seq = request_scan_seq-1;      /* invalidate */
1665     entity->  value_scan.seq =   value_scan_seq-1;      /* invalidate */
1666     entity->   eval_scan.seq =    eval_scan_seq-1;      /* invalidate */
1667     tac_list_init(&entity->eval_scan.notify_expr_list);
1668     tac_list_node_init(&entity->eval_scan.pending_entity_node);
1669 }
1670
1671 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1672
1673 struct membership *
1674 enlist_entity_direct(parent, child, when)
1675 ENTITY *parent;
1676 ENTITY *child;
1677 struct expr *when;
1678 {
1679     struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1680
1681     tac_list_node_init(&membership->parent_node);
1682     tac_list_node_init(&membership->child_node);
1683     membership->request_scan.seq = request_scan_seq-1;
1684     tac_list_node_init(&membership->request_scan.virtual_membership_node);
1685     membership->eval_scan.seq = eval_scan_seq-1;
1686
1687     tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1688     parent->to_child_membership_num++;
1689     tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1690     membership->when = when;
1691     if (expr_sink(membership->when, membership)) {
1692         unlink_membership(membership);
1693         free_membership(membership);
1694         return (NULL);
1695     }
1696
1697     if (debug & DEBUG_CFGEVAL_FLAG)
1698         report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1699                 PA_MEMBERSHIP(membership));
1700
1701     return (membership);
1702 }
1703
1704 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1705
1706 struct membership *
1707 virtual_enlist_entity_direct(parent, child)
1708 ENTITY *parent;
1709 ENTITY *child;
1710 {
1711     struct membership *membership;
1712
1713     if (debug & DEBUG_CFGEVAL_FLAG)
1714         report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1715
1716     membership = enlist_entity_direct(parent, child, NULL /* when */);
1717     if (!membership)
1718         return (NULL);
1719
1720     check_request_scan_membership(membership, 0);
1721     tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1722
1723     return (membership);
1724 }
1725
1726 /* returns given 'entity' or NULL if already visited */
1727
1728 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1729
1730 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1731
1732 static ENTITY *
1733 value_scan_forward(membership)
1734 struct membership *membership;
1735 {
1736     ENTITY *parent_entity;
1737
1738     if (debug & DEBUG_CFGEVAL_FLAG)
1739         report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1740                 PA_MEMBERSHIP(membership));
1741
1742     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1743
1744     if (ER_TRUE != expr_eval(membership->when)) {
1745         if (debug & DEBUG_CFGEVAL_FLAG)
1746             report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1747         return (NULL);
1748     }
1749     check_value_scan_entity(parent_entity, 0);
1750     if (parent_entity->value_scan.seen) {
1751         if (debug & DEBUG_CFGEVAL_FLAG)
1752             report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1753                     PA_ENTITY(parent_entity));
1754         if (value_scan_forward_seen_hook)
1755             (*value_scan_forward_seen_hook)(membership);
1756         return (NULL);
1757     }
1758     parent_entity->value_scan.seen = 1;
1759     parent_entity->value_scan.from = membership;
1760
1761     if (debug & DEBUG_CFGEVAL_FLAG)
1762         report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1763                 PA_ENTITY(parent_entity));
1764     return (parent_entity);
1765 }
1766
1767 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1768
1769 struct membership *
1770 value_scan_backward(entity)
1771 ENTITY *entity;
1772 {
1773     if (debug & DEBUG_CFGEVAL_FLAG)
1774         report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1775                 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1776
1777 #ifdef SCAN_PARANOIA
1778     if (entity->value_scan.seq != value_scan_seq) {
1779         report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1780         return (NULL);
1781     }
1782 #endif
1783
1784     return (entity->value_scan.from);
1785 }
1786
1787 /* Scan the entity graph and return each node found.
1788    'when' conditions for graph connections are respected,
1789    looping is correctly prevented.
1790 */
1791
1792 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1793
1794 enum value_scan_func_result
1795 value_scan_entity(entity, recurse, func, func_data)
1796 ENTITY *entity;
1797 int recurse;
1798 value_scan_func_t func;
1799 void *func_data;
1800 {
1801     enum value_scan_func_result vsfr;
1802     struct tac_list_node *membership_node;
1803
1804     if (debug & DEBUG_CFGEVAL_FLAG)
1805         report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1806                 PA_ENTITY(entity), recurse);
1807
1808     vsfr=(*func)(entity,func_data);
1809
1810     if (debug & DEBUG_CFGEVAL_FLAG)
1811         report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1812                 PA_VSFR(vsfr));
1813
1814     if (vsfr != VSFR_CONTINUE) {
1815         if (debug & DEBUG_CFGEVAL_FLAG)
1816             report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1817         return (vsfr);
1818     }
1819     if (!recurse ) {
1820         if (debug & DEBUG_CFGEVAL_FLAG)
1821             report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1822         return (VSFR_STOP);
1823     }
1824
1825     value_scan_begin(entity);
1826     membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1827     if (!membership_node) {
1828         if (debug & DEBUG_CFGEVAL_FLAG)
1829             report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1830         return (VSFR_CONTINUE);         /* no parent entities */
1831     }
1832
1833     while (1) {
1834         struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1835
1836         if (debug & DEBUG_CFGEVAL_FLAG)
1837             report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1838                     PA_MEMBERSHIP(membership));
1839
1840         entity = value_scan_forward(membership);
1841         if (entity) {
1842             if (debug & DEBUG_CFGEVAL_FLAG)
1843                 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1844                         PA_ENTITY(entity));
1845
1846             vsfr=(*func)(entity,func_data);
1847
1848             if (debug & DEBUG_CFGEVAL_FLAG)
1849                 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1850                         PA_ENTITY(entity), PA_VSFR(vsfr));
1851
1852             if (vsfr == VSFR_FOUND) {
1853                 if (debug & DEBUG_CFGEVAL_FLAG)
1854                     report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1855                 return (vsfr);
1856             }
1857             if (vsfr == VSFR_CONTINUE)
1858                 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1859         }
1860         if (!entity || vsfr == VSFR_STOP) {
1861             ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1862
1863             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1864
1865             if (debug & DEBUG_CFGEVAL_FLAG)
1866                 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1867                         PA_ENTITY(parent_entity), PA_ENTITY(entity));
1868
1869             membership_node = tac_list_node_next(&membership->child_node);
1870         }
1871
1872         while (!membership_node) {
1873             membership = value_scan_backward(entity);
1874             if (!membership) {
1875                 if (debug & DEBUG_CFGEVAL_FLAG)
1876                     report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1877                 return (VSFR_CONTINUE);         /* FINISH */
1878             }
1879
1880             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1881
1882             if (debug & DEBUG_CFGEVAL_FLAG)
1883                 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1884                                 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1885                                 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1886
1887             membership_node = tac_list_node_next(&membership->child_node);
1888         }
1889     }
1890     /* NOTREACHED */
1891 }