Multiple childs of membership are now respected (not only the first one)
[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         return;
1072
1073     tac_list_addtail(&entity->eval_scan.notify_expr_list,
1074             &expr->eval_scan.u.entity.notify_expr_node);
1075
1076     register_kicked_entity(entity, 0 /* priority */);
1077 }
1078
1079 /* check_eval_scan_*() is assumed for "expr" ! */
1080
1081 static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
1082
1083 static void
1084 expr_eval_notify_expr_remove_internal(expr)
1085 struct expr *expr;
1086 {
1087     if (debug & DEBUG_CFGEVAL_FLAG)
1088         report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
1089                 PA_EXPR(expr));
1090
1091     if (!expr)
1092         return;
1093     if (expr->eval_scan.seq != eval_scan_seq)
1094         return;
1095     if (expr->request_scan.result != ER_UNKNOWN)
1096         return;
1097
1098     switch (expr->type) {
1099
1100     case S_not:
1101         expr_eval_notify_expr_remove_internal(expr->u.not.child);
1102         break;
1103
1104     case S_and:
1105     case S_or: {
1106         struct expr *child;
1107
1108         for (child=expr->u.and_or.child_first; child; child=child->next)
1109             expr_eval_notify_expr_remove_internal(child);
1110         } break;
1111
1112     case S_user:
1113     case S_host:
1114     case S_group: {
1115         ENTITY *entity = expr->u.entity.entity;
1116         struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1117
1118         if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1119             break;
1120
1121         tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
1122         if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
1123             break;
1124         /* no one is further interested in "entity" */
1125
1126         if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
1127             tac_list_node_remove (pending_entity_node);
1128             if (debug & DEBUG_CFGEVAL_FLAG)
1129                 report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
1130                         PA_ENTITY(entity));
1131         }
1132         if (tac_list_node_get_list(pending_entity_node) == NULL) {
1133             tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
1134             if (debug & DEBUG_CFGEVAL_FLAG)
1135                 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
1136                         PA_ENTITY(entity));
1137         }
1138 #ifdef SCAN_PARANOIA
1139         if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
1140             report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1141             return;
1142         }
1143 #endif
1144
1145         } break;
1146
1147     default:
1148         report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
1149         return;
1150     }
1151 }
1152
1153 static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
1154
1155 static void expr_eval_notify_expr_flush_destroy_entity_list()
1156 {
1157 struct tac_list_node *destroy_entity_node;
1158
1159     while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
1160         ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
1161         struct tac_list_node *destroy_notify_expr_node;
1162
1163         if (debug & DEBUG_CFGEVAL_FLAG)
1164             report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
1165                     PA_ENTITY(destroy_entity));
1166
1167         while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
1168             struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
1169
1170             expr_eval_notify_expr_remove_internal(destroy_notify_expr);
1171         }
1172     }
1173 }
1174
1175 static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
1176
1177 static void
1178 expr_eval_notify_expr_remove(expr)
1179 struct expr *expr;
1180 {
1181     if (debug & DEBUG_CFGEVAL_FLAG)
1182         report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
1183                 PA_EXPR(expr));
1184
1185     expr_eval_notify_expr_remove_internal(expr);
1186     expr_eval_notify_expr_flush_destroy_entity_list();
1187 }
1188
1189 /* It would be very nice to try to optimize the expression before evaluation.
1190
1191    We are not interested in some CPU time complexity of the expression.
1192    But we would be very happy to discard any user/host/group membership
1193    dependencies (our 'variables'). Unfortunately such optimization is
1194    NP problem (classification by courtesy of Daniel Kral) so it is considered
1195    too expensive for us.
1196
1197    TODO in future: Full NP optimization for small number of variables and/or
1198    heuristic optimizations for complex expressions.
1199 */
1200
1201 static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
1202
1203 static enum eval_result
1204 expr_eval_immediate(expr_single)
1205 struct expr *expr_single;
1206 {
1207     struct expr *expr_child, *expr_parent;
1208     enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
1209
1210     if (debug & DEBUG_CFGEVAL_FLAG)
1211         report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
1212                 PA_EXPR(expr_single));
1213
1214     if (!expr_single)
1215         return (ER_TRUE);
1216
1217     /* TOP->DOWN scanner: */
1218 top_down:
1219     while (1) {
1220         enum eval_result result_single;
1221
1222         if (debug & DEBUG_CFGEVAL_FLAG)
1223             report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
1224                     PA_EXPR(expr_single));
1225
1226         check_eval_scan_expr(expr_single, 0);
1227         result_single = expr_single->request_scan.result;
1228         if (result_single != ER_UNKNOWN)
1229             break;
1230         switch (expr_single->type) {
1231
1232         case S_not:
1233             expr_single = expr_single->u.not.child;
1234             continue;
1235
1236         case S_and:
1237         case S_or:
1238             expr_single = expr_single->u.and_or.child_first;
1239             continue;
1240
1241         case S_user:
1242         case S_host:
1243         case S_group: {
1244             ENTITY *entity = expr_single->u.entity.entity;
1245
1246             check_eval_scan_entity(entity, 0);
1247
1248             if (entity->request_scan.belongs == ER_UNKNOWN)
1249                 expr_eval_notify_expr(expr_single);
1250             else
1251                 result_single = entity->request_scan.belongs;
1252             } break;
1253
1254         default:
1255             report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
1256             return (ER_UNKNOWN);
1257         }
1258
1259         expr_single->request_scan.result = result_single;
1260         break;
1261     }
1262
1263     /* BOTTOM->UP scanner: */
1264     do {
1265         if (debug & DEBUG_CFGEVAL_FLAG)
1266             report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
1267                     PA_EXPR(expr_single));
1268
1269         expr_parent = expr_single->parent;
1270         if (!expr_parent)
1271             break;
1272         if (expr_parent->eval_scan.seq != eval_scan_seq) {
1273             report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
1274             return (ER_UNKNOWN);
1275         }
1276         if (expr_parent->request_scan.seq != request_scan_seq) {
1277             report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
1278             return (ER_UNKNOWN);
1279         }
1280         if (expr_parent->request_scan.result != ER_UNKNOWN) {
1281             report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
1282             return (ER_UNKNOWN);
1283         }
1284
1285         expr_child = expr_single;
1286         result_child = expr_child->request_scan.result;
1287
1288         if (debug & DEBUG_CFGEVAL_FLAG)
1289             report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
1290                     PA_EXPR(expr_child), PA_EXPR(expr_parent));
1291
1292         switch (expr_parent->type) {
1293
1294         case S_not:
1295             switch (result_child) {
1296             case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
1297             case ER_FALSE:   result_parent = ER_TRUE;    break;
1298             case ER_TRUE:    result_parent = ER_FALSE;   break;
1299             }
1300             break;
1301
1302         case S_and:
1303         case S_or: {
1304             enum eval_result veto    = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
1305             enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE  : ER_FALSE);
1306
1307                  if (result_child == veto)
1308                 result_parent = veto;
1309             else if (result_child == ER_UNKNOWN || result_child == consent) {
1310                 if (expr_child->next) {
1311                     expr_single = expr_child->next;
1312                     if (debug & DEBUG_CFGEVAL_FLAG)
1313                         report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
1314                                 PA_EXPR(expr_single));
1315                     goto top_down;
1316                 }
1317
1318                 if (debug & DEBUG_CFGEVAL_FLAG)
1319                     report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
1320                             PA_EXPR(expr_single));
1321
1322                 result_parent = consent;
1323                 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1324                 {
1325                     check_eval_scan_expr(expr_child, 0);        /* shouldn't be needed */
1326                          if (expr_child->request_scan.result == ER_UNKNOWN)
1327                         result_parent = ER_UNKNOWN;     /* assumed (result_parent != veto) */
1328                     else if (expr_child->request_scan.result == veto) {
1329                         result_parent = veto;
1330                         break;
1331                     }
1332                 }
1333                 break;
1334             }
1335             } break;
1336
1337         default:
1338             report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1339             return (ER_UNKNOWN);
1340         }
1341
1342         if (debug & DEBUG_CFGEVAL_FLAG)
1343             report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1344                     PA_EXPR(expr_child), PA_EXPR(expr_parent));
1345
1346         if (result_parent != ER_UNKNOWN) {
1347             expr_parent->request_scan.result = result_parent;
1348             /* we no longer need any notifications from entities to solve sub-expression */
1349             expr_eval_notify_expr_remove(expr_parent);
1350         }
1351
1352         expr_single = expr_parent;
1353     } while (0);
1354     /* The whole expression has been scanned to its root, we have "expr_single" */
1355
1356     if (debug & DEBUG_CFGEVAL_FLAG)
1357         report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1358                 PA_EXPR(expr_single));
1359
1360     return (expr_single->request_scan.result);
1361 }
1362
1363 static void membership_solved TAC_ARGS((struct membership *membership));
1364
1365 static void
1366 membership_solved(membership)
1367 struct membership *membership;
1368 {
1369     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1370
1371     check_request_scan_entity(parent_entity, 0);
1372
1373 #ifdef SCAN_PARANOIA
1374     if (!membership->eval_scan.unsolved) {
1375         report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1376         return;
1377     }
1378 #endif
1379
1380     membership->eval_scan.unsolved = 0;
1381
1382 #ifdef SCAN_PARANOIA
1383     if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1384         report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1385         parent_entity->eval_scan.unsolved_to_child_membership_num++;
1386     }
1387 #endif
1388     parent_entity->eval_scan.unsolved_to_child_membership_num--;
1389
1390     if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1391      && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1392         parent_entity->request_scan.belongs = ER_FALSE;
1393         register_kicked_entity(parent_entity, 1 /* priority */);
1394     }
1395 }
1396
1397 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1398
1399 static void
1400 membership_parent_solve(membership, how)
1401 struct membership *membership;
1402 enum eval_result how;
1403 {
1404     enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1405     ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1406
1407     check_request_scan_entity(parent_entity, 0);
1408
1409     if (parent_entity->request_scan.belongs == negative)
1410         report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1411                 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1412
1413     parent_entity->request_scan.belongs = how;
1414     register_kicked_entity(parent_entity, 1 /* priority */);
1415
1416     membership_solved(membership);
1417
1418     if (debug & DEBUG_CFGEVAL_FLAG)
1419         report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1420                 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1421 }
1422
1423 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1424
1425 static void
1426 membership_eval_immediate(membership)
1427 struct membership *membership;
1428 {
1429     enum eval_result membership_valid;
1430     ENTITY *child_entity, *parent_entity;
1431
1432     if (debug & DEBUG_CFGEVAL_FLAG)
1433         report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1434                 PA_MEMBERSHIP(membership));
1435
1436     check_eval_scan_membership(membership, 0);
1437
1438     if (!membership->eval_scan.unsolved)
1439         return;
1440     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1441     check_request_scan_entity(parent_entity, 0);
1442     if (parent_entity->request_scan.belongs != ER_UNKNOWN)      /* why to solve this membership? */
1443         return;
1444
1445     membership_valid = expr_eval_immediate(membership->when);
1446
1447     child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1448     check_request_scan_entity( child_entity, 0);
1449
1450 #if 0 /* non-valid membership doesn't YET solve the parent! */
1451     if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1452         membership_parent_solve(membership, ER_FALSE);
1453         return;
1454     }
1455 #endif
1456
1457     if (child_entity->request_scan.belongs == ER_TRUE  && membership_valid == ER_TRUE ) {
1458         membership_parent_solve(membership, ER_TRUE );
1459         return;
1460     }
1461
1462     if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1463         register_kicked_entity( child_entity, 0 /* priority */);
1464     if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1465         register_kicked_entity(parent_entity, 0 /* priority */);
1466
1467     if (parent_entity->request_scan.belongs != ER_UNKNOWN
1468      || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1469         membership_solved(membership);
1470
1471     if (debug & DEBUG_CFGEVAL_FLAG)
1472         report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1473                 PA_MEMBERSHIP(membership));
1474 }
1475
1476 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1477
1478 static void
1479 entity_eval_immediate(entity)
1480 ENTITY *entity;
1481 {
1482     struct tac_list_node *notified_expr_node;
1483     struct tac_list_node *child_membership_node;
1484
1485     if (debug & DEBUG_CFGEVAL_FLAG)
1486         report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1487                 PA_ENTITY(entity));
1488
1489     check_eval_scan_entity(entity, 0);
1490
1491     if (!request_scan_user_known) {
1492 #ifdef SCAN_PARANOIA
1493         if (entity->request_scan.belongs != ER_UNKNOWN)
1494             report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1495                     PA_ENTITY(entity));
1496 #endif
1497         return;
1498     }
1499
1500     if (entity->request_scan.belongs == ER_UNKNOWN) {
1501         if (entity->eval_scan.unsolved_to_child_membership_first) {
1502             struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1503             struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1504
1505             membership_eval_immediate(order_membership);
1506             if (next_membership_parent_node)
1507                 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1508             else
1509                 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1510
1511             register_kicked_entity(entity, 0 /* priority */);
1512
1513             if (debug & DEBUG_CFGEVAL_FLAG)
1514                 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1515                         PA_MEMBERSHIP(order_membership));
1516             return;
1517         }
1518
1519         if (!entity->eval_scan.unsolved_to_child_membership_num)
1520             entity->request_scan.belongs = ER_FALSE;
1521         else {
1522             if (debug & DEBUG_CFGEVAL_FLAG)
1523                 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1524             return;
1525         }
1526     }
1527     /* belonging is known here */
1528
1529     /* recheck all memberships we may decide */
1530     for (
1531             child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1532             child_membership_node;
1533             child_membership_node = tac_list_node_next(child_membership_node)
1534             ) {
1535         struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1536
1537         membership_eval_immediate(child_membership);
1538     }
1539
1540     /* notify all exprs which are interested in us */
1541     while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1542         tac_list_node_remove(notified_expr_node);
1543         tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1544     }
1545
1546     if (debug & DEBUG_CFGEVAL_FLAG)
1547         report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1548                 PA_ENTITY(entity));
1549 }
1550
1551
1552 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1553
1554 enum eval_result
1555 expr_eval(expr)
1556 struct expr *expr;
1557 {
1558     if (debug & DEBUG_CFGEVAL_FLAG)
1559         report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1560                 PA_EXPR(expr));
1561
1562     if (!expr)
1563         return (ER_TRUE);
1564
1565     eval_scan_begin();
1566     if (expr_eval_immediate(expr) != ER_UNKNOWN)
1567         return (expr->request_scan.result);
1568
1569     /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1570      * otherwise we may have no longer valid node!
1571      */
1572     for (;;) {
1573         struct tac_list_node *notified_expr_node, *kicked_entity_node;
1574
1575         /* check it rather always, checking just on notifications looks too complex.
1576         */
1577         if (expr->request_scan.result != ER_UNKNOWN) {
1578             if (debug & DEBUG_CFGEVAL_FLAG)
1579                 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1580                         PA_EXPR(expr));
1581             return (expr->request_scan.result);
1582         }
1583
1584 #if 0   /* not needed as it is now always called after any destroy */
1585         expr_eval_notify_expr_flush_destroy_entity_list();      /* eval_destroy_entity_list */
1586 #endif  /* not needed */
1587
1588         if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1589             struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1590
1591             if (debug & DEBUG_CFGEVAL_FLAG)
1592                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1593                         PA_EXPR(notified_expr));
1594
1595             tac_list_node_remove(notified_expr_node);
1596             expr_eval_immediate(notified_expr);
1597
1598             if (notified_expr->membership)
1599                 membership_eval_immediate(notified_expr->membership);
1600
1601             continue;           /* shortcut */
1602         }
1603
1604         if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1605             ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1606
1607             if (debug & DEBUG_CFGEVAL_FLAG)
1608                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1609                         PA_ENTITY(kicked_entity));
1610
1611             tac_list_node_remove(kicked_entity_node);
1612             entity_eval_immediate(kicked_entity);
1613             continue;           /* shortcut */
1614         }
1615
1616         break;  /* nothing done yet, all lists are empty! */
1617     }
1618
1619     if (!expr->request_scan.loop_reported) {
1620         report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1621         expr->request_scan.loop_reported = 1;
1622     }
1623     return (ER_UNKNOWN);
1624 }
1625
1626
1627 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1628
1629 void eval_force_belong_entity(entity)
1630 ENTITY *entity;
1631 {
1632     if (debug & DEBUG_CFGEVAL_FLAG)
1633         report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1634                 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1635
1636     check_request_scan_entity(entity, 0);
1637
1638     if (entity->request_scan.belongs == ER_FALSE)
1639         report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1640
1641     entity->request_scan.belongs = ER_TRUE;
1642 }
1643
1644 void scan_init_entity TAC_ARGS((ENTITY *entity));
1645
1646 void
1647 scan_init_entity(entity)
1648 ENTITY *entity;
1649 {
1650     entity->request_scan.seq = request_scan_seq-1;      /* invalidate */
1651     entity->  value_scan.seq =   value_scan_seq-1;      /* invalidate */
1652     entity->   eval_scan.seq =    eval_scan_seq-1;      /* invalidate */
1653     tac_list_init(&entity->eval_scan.notify_expr_list);
1654     tac_list_node_init(&entity->eval_scan.pending_entity_node);
1655 }
1656
1657 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1658
1659 struct membership *
1660 enlist_entity_direct(parent, child, when)
1661 ENTITY *parent;
1662 ENTITY *child;
1663 struct expr *when;
1664 {
1665     struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1666
1667     tac_list_node_init(&membership->parent_node);
1668     tac_list_node_init(&membership->child_node);
1669     membership->request_scan.seq = request_scan_seq-1;
1670     tac_list_node_init(&membership->request_scan.virtual_membership_node);
1671     membership->eval_scan.seq = eval_scan_seq-1;
1672
1673     tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1674     parent->to_child_membership_num++;
1675     tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1676     membership->when = when;
1677     if (expr_sink(membership->when, membership)) {
1678         unlink_membership(membership);
1679         free_membership(membership);
1680         return (NULL);
1681     }
1682
1683     if (debug & DEBUG_CFGEVAL_FLAG)
1684         report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1685                 PA_MEMBERSHIP(membership));
1686
1687     return (membership);
1688 }
1689
1690 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1691
1692 struct membership *
1693 virtual_enlist_entity_direct(parent, child)
1694 ENTITY *parent;
1695 ENTITY *child;
1696 {
1697     struct membership *membership;
1698
1699     if (debug & DEBUG_CFGEVAL_FLAG)
1700         report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1701
1702     membership = enlist_entity_direct(parent, child, NULL /* when */);
1703     if (!membership)
1704         return (NULL);
1705
1706     check_request_scan_membership(membership, 0);
1707     tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1708
1709     return (membership);
1710 }
1711
1712 /* returns given 'entity' or NULL if already visited */
1713
1714 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1715
1716 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1717
1718 static ENTITY *
1719 value_scan_forward(membership)
1720 struct membership *membership;
1721 {
1722     ENTITY *parent_entity;
1723
1724     if (debug & DEBUG_CFGEVAL_FLAG)
1725         report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1726                 PA_MEMBERSHIP(membership));
1727
1728     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1729
1730     if (ER_TRUE != expr_eval(membership->when)) {
1731         if (debug & DEBUG_CFGEVAL_FLAG)
1732             report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1733         return (NULL);
1734     }
1735     check_value_scan_entity(parent_entity, 0);
1736     if (parent_entity->value_scan.seen) {
1737         if (debug & DEBUG_CFGEVAL_FLAG)
1738             report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1739                     PA_ENTITY(parent_entity));
1740         if (value_scan_forward_seen_hook)
1741             (*value_scan_forward_seen_hook)(membership);
1742         return (NULL);
1743     }
1744     parent_entity->value_scan.seen = 1;
1745     parent_entity->value_scan.from = membership;
1746
1747     if (debug & DEBUG_CFGEVAL_FLAG)
1748         report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1749                 PA_ENTITY(parent_entity));
1750     return (parent_entity);
1751 }
1752
1753 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1754
1755 struct membership *
1756 value_scan_backward(entity)
1757 ENTITY *entity;
1758 {
1759     if (debug & DEBUG_CFGEVAL_FLAG)
1760         report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1761                 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1762
1763 #ifdef SCAN_PARANOIA
1764     if (entity->value_scan.seq != value_scan_seq) {
1765         report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1766         return (NULL);
1767     }
1768 #endif
1769
1770     return (entity->value_scan.from);
1771 }
1772
1773 /* Scan the entity graph and return each node found.
1774    'when' conditions for graph connections are respected,
1775    looping is correctly prevented.
1776 */
1777
1778 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1779
1780 enum value_scan_func_result
1781 value_scan_entity(entity, recurse, func, func_data)
1782 ENTITY *entity;
1783 int recurse;
1784 value_scan_func_t func;
1785 void *func_data;
1786 {
1787     enum value_scan_func_result vsfr;
1788     struct tac_list_node *membership_node;
1789
1790     if (debug & DEBUG_CFGEVAL_FLAG)
1791         report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1792                 PA_ENTITY(entity), recurse);
1793
1794     vsfr=(*func)(entity,func_data);
1795
1796     if (debug & DEBUG_CFGEVAL_FLAG)
1797         report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1798                 PA_VSFR(vsfr));
1799
1800     if (vsfr != VSFR_CONTINUE) {
1801         if (debug & DEBUG_CFGEVAL_FLAG)
1802             report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1803         return (vsfr);
1804     }
1805     if (!recurse ) {
1806         if (debug & DEBUG_CFGEVAL_FLAG)
1807             report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1808         return (VSFR_STOP);
1809     }
1810
1811     value_scan_begin(entity);
1812     membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1813     if (!membership_node) {
1814         if (debug & DEBUG_CFGEVAL_FLAG)
1815             report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1816         return (VSFR_CONTINUE);         /* no parent entities */
1817     }
1818
1819     while (1) {
1820         struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1821
1822         if (debug & DEBUG_CFGEVAL_FLAG)
1823             report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1824                     PA_MEMBERSHIP(membership));
1825
1826         entity = value_scan_forward(membership);
1827         if (entity) {
1828             if (debug & DEBUG_CFGEVAL_FLAG)
1829                 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1830                         PA_ENTITY(entity));
1831
1832             vsfr=(*func)(entity,func_data);
1833
1834             if (debug & DEBUG_CFGEVAL_FLAG)
1835                 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1836                         PA_ENTITY(entity), PA_VSFR(vsfr));
1837
1838             if (vsfr == VSFR_FOUND) {
1839                 if (debug & DEBUG_CFGEVAL_FLAG)
1840                     report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1841                 return (vsfr);
1842             }
1843             if (vsfr == VSFR_CONTINUE)
1844                 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1845         }
1846         if (!entity || vsfr == VSFR_STOP) {
1847             ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1848
1849             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1850
1851             if (debug & DEBUG_CFGEVAL_FLAG)
1852                 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1853                         PA_ENTITY(parent_entity), PA_ENTITY(entity));
1854
1855             membership_node = tac_list_node_next(&membership->child_node);
1856         }
1857
1858         while (!membership_node) {
1859             membership = value_scan_backward(entity);
1860             if (!membership) {
1861                 if (debug & DEBUG_CFGEVAL_FLAG)
1862                     report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1863                 return (VSFR_CONTINUE);         /* FINISH */
1864             }
1865
1866             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1867
1868             if (debug & DEBUG_CFGEVAL_FLAG)
1869                 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1870                                 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1871                                 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1872
1873             membership_node = tac_list_node_next(&membership->child_node);
1874         }
1875     }
1876     /* NOTREACHED */
1877 }