Cosmetic: Indentation.
[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 (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1451         membership_parent_solve(membership, ER_FALSE);
1452         return;
1453     }
1454     if (child_entity->request_scan.belongs == ER_TRUE  && membership_valid == ER_TRUE ) {
1455         membership_parent_solve(membership, ER_TRUE );
1456         return;
1457     }
1458
1459     if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1460         register_kicked_entity( child_entity, 0 /* priority */);
1461     if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1462         register_kicked_entity(parent_entity, 0 /* priority */);
1463
1464     if ( child_entity->request_scan.belongs != ER_UNKNOWN
1465      && parent_entity->request_scan.belongs != ER_UNKNOWN)
1466         membership_solved(membership);
1467
1468     if (debug & DEBUG_CFGEVAL_FLAG)
1469         report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1470                 PA_MEMBERSHIP(membership));
1471 }
1472
1473 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1474
1475 static void
1476 entity_eval_immediate(entity)
1477 ENTITY *entity;
1478 {
1479     struct tac_list_node *notified_expr_node;
1480     struct tac_list_node *child_membership_node;
1481
1482     if (debug & DEBUG_CFGEVAL_FLAG)
1483         report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1484                 PA_ENTITY(entity));
1485
1486     check_eval_scan_entity(entity, 0);
1487
1488     if (!request_scan_user_known) {
1489 #ifdef SCAN_PARANOIA
1490         if (entity->request_scan.belongs != ER_UNKNOWN)
1491             report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1492                     PA_ENTITY(entity));
1493 #endif
1494         return;
1495     }
1496
1497     if (entity->request_scan.belongs == ER_UNKNOWN) {
1498         if (entity->eval_scan.unsolved_to_child_membership_first) {
1499             struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1500             struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1501
1502             membership_eval_immediate(order_membership);
1503             if (next_membership_parent_node)
1504                 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1505             else
1506                 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1507
1508             register_kicked_entity(entity, 0 /* priority */);
1509
1510             if (debug & DEBUG_CFGEVAL_FLAG)
1511                 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1512                         PA_MEMBERSHIP(order_membership));
1513             return;
1514         }
1515
1516         if (!entity->eval_scan.unsolved_to_child_membership_num)
1517             entity->request_scan.belongs = ER_FALSE;
1518         else {
1519             if (debug & DEBUG_CFGEVAL_FLAG)
1520                 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1521             return;
1522         }
1523     }
1524     /* belonging is known here */
1525
1526     /* recheck all memberships we may decide */
1527     for (
1528             child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1529             child_membership_node;
1530             child_membership_node = tac_list_node_next(child_membership_node)
1531             ) {
1532         struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1533
1534         membership_eval_immediate(child_membership);
1535     }
1536
1537     /* notify all exprs which are interested in us */
1538     while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1539         tac_list_node_remove(notified_expr_node);
1540         tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1541     }
1542
1543     if (debug & DEBUG_CFGEVAL_FLAG)
1544         report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1545                 PA_ENTITY(entity));
1546 }
1547
1548
1549 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1550
1551 enum eval_result
1552 expr_eval(expr)
1553 struct expr *expr;
1554 {
1555     if (debug & DEBUG_CFGEVAL_FLAG)
1556         report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1557                 PA_EXPR(expr));
1558
1559     if (!expr)
1560         return (ER_TRUE);
1561
1562     eval_scan_begin();
1563     if (expr_eval_immediate(expr) != ER_UNKNOWN)
1564         return (expr->request_scan.result);
1565
1566     /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1567      * otherwise we may have no longer valid node!
1568      */
1569     for (;;) {
1570         struct tac_list_node *notified_expr_node, *kicked_entity_node;
1571
1572         /* check it rather always, checking just on notifications looks too complex.
1573         */
1574         if (expr->request_scan.result != ER_UNKNOWN) {
1575             if (debug & DEBUG_CFGEVAL_FLAG)
1576                 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1577                         PA_EXPR(expr));
1578             return (expr->request_scan.result);
1579         }
1580
1581 #if 0   /* not needed as it is now always called after any destroy */
1582         expr_eval_notify_expr_flush_destroy_entity_list();      /* eval_destroy_entity_list */
1583 #endif  /* not needed */
1584
1585         if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1586             struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1587
1588             if (debug & DEBUG_CFGEVAL_FLAG)
1589                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1590                         PA_EXPR(notified_expr));
1591
1592             tac_list_node_remove(notified_expr_node);
1593             expr_eval_immediate(notified_expr);
1594
1595             if (notified_expr->membership)
1596                 membership_eval_immediate(notified_expr->membership);
1597
1598             continue;           /* shortcut */
1599         }
1600
1601         if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1602             ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1603
1604             if (debug & DEBUG_CFGEVAL_FLAG)
1605                 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1606                         PA_ENTITY(kicked_entity));
1607
1608             tac_list_node_remove(kicked_entity_node);
1609             entity_eval_immediate(kicked_entity);
1610             continue;           /* shortcut */
1611         }
1612
1613         break;  /* nothing done yet, all lists are empty! */
1614     }
1615
1616     if (!expr->request_scan.loop_reported) {
1617         report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1618         expr->request_scan.loop_reported = 1;
1619     }
1620     return (ER_UNKNOWN);
1621 }
1622
1623
1624 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1625
1626 void eval_force_belong_entity(entity)
1627 ENTITY *entity;
1628 {
1629     if (debug & DEBUG_CFGEVAL_FLAG)
1630         report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1631                 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1632
1633     check_request_scan_entity(entity, 0);
1634
1635     if (entity->request_scan.belongs == ER_FALSE)
1636         report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1637
1638     entity->request_scan.belongs = ER_TRUE;
1639 }
1640
1641 void scan_init_entity TAC_ARGS((ENTITY *entity));
1642
1643 void
1644 scan_init_entity(entity)
1645 ENTITY *entity;
1646 {
1647     entity->request_scan.seq = request_scan_seq-1;      /* invalidate */
1648     entity->  value_scan.seq =   value_scan_seq-1;      /* invalidate */
1649     entity->   eval_scan.seq =    eval_scan_seq-1;      /* invalidate */
1650     tac_list_init(&entity->eval_scan.notify_expr_list);
1651     tac_list_node_init(&entity->eval_scan.pending_entity_node);
1652 }
1653
1654 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1655
1656 struct membership *
1657 enlist_entity_direct(parent, child, when)
1658 ENTITY *parent;
1659 ENTITY *child;
1660 struct expr *when;
1661 {
1662     struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1663
1664     tac_list_node_init(&membership->parent_node);
1665     tac_list_node_init(&membership->child_node);
1666     membership->request_scan.seq = request_scan_seq-1;
1667     tac_list_node_init(&membership->request_scan.virtual_membership_node);
1668     membership->eval_scan.seq = eval_scan_seq-1;
1669
1670     tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1671     parent->to_child_membership_num++;
1672     tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1673     membership->when = when;
1674     if (expr_sink(membership->when, membership)) {
1675         unlink_membership(membership);
1676         free_membership(membership);
1677         return (NULL);
1678     }
1679
1680     if (debug & DEBUG_CFGEVAL_FLAG)
1681         report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1682                 PA_MEMBERSHIP(membership));
1683
1684     return (membership);
1685 }
1686
1687 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1688
1689 struct membership *
1690 virtual_enlist_entity_direct(parent, child)
1691 ENTITY *parent;
1692 ENTITY *child;
1693 {
1694     struct membership *membership;
1695
1696     if (debug & DEBUG_CFGEVAL_FLAG)
1697         report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1698
1699     membership = enlist_entity_direct(parent, child, NULL /* when */);
1700     if (!membership)
1701         return (NULL);
1702
1703     check_request_scan_membership(membership, 0);
1704     tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1705
1706     return (membership);
1707 }
1708
1709 /* returns given 'entity' or NULL if already visited */
1710
1711 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1712
1713 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1714
1715 static ENTITY *
1716 value_scan_forward(membership)
1717 struct membership *membership;
1718 {
1719     ENTITY *parent_entity;
1720
1721     if (debug & DEBUG_CFGEVAL_FLAG)
1722         report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1723                 PA_MEMBERSHIP(membership));
1724
1725     parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1726
1727     if (ER_TRUE != expr_eval(membership->when)) {
1728         if (debug & DEBUG_CFGEVAL_FLAG)
1729             report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1730         return (NULL);
1731     }
1732     check_value_scan_entity(parent_entity, 0);
1733     if (parent_entity->value_scan.seen) {
1734         if (debug & DEBUG_CFGEVAL_FLAG)
1735             report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1736                     PA_ENTITY(parent_entity));
1737         if (value_scan_forward_seen_hook)
1738             (*value_scan_forward_seen_hook)(membership);
1739         return (NULL);
1740     }
1741     parent_entity->value_scan.seen = 1;
1742     parent_entity->value_scan.from = membership;
1743
1744     if (debug & DEBUG_CFGEVAL_FLAG)
1745         report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1746                 PA_ENTITY(parent_entity));
1747     return (parent_entity);
1748 }
1749
1750 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1751
1752 struct membership *
1753 value_scan_backward(entity)
1754 ENTITY *entity;
1755 {
1756     if (debug & DEBUG_CFGEVAL_FLAG)
1757         report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1758                 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1759
1760 #ifdef SCAN_PARANOIA
1761     if (entity->value_scan.seq != value_scan_seq) {
1762         report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1763         return (NULL);
1764     }
1765 #endif
1766
1767     return (entity->value_scan.from);
1768 }
1769
1770 /* Scan the entity graph and return each node found.
1771    'when' conditions for graph connections are respected,
1772    looping is correctly prevented.
1773 */
1774
1775 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1776
1777 enum value_scan_func_result
1778 value_scan_entity(entity, recurse, func, func_data)
1779 ENTITY *entity;
1780 int recurse;
1781 value_scan_func_t func;
1782 void *func_data;
1783 {
1784     enum value_scan_func_result vsfr;
1785     struct tac_list_node *membership_node;
1786
1787     if (debug & DEBUG_CFGEVAL_FLAG)
1788         report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1789                 PA_ENTITY(entity), recurse);
1790
1791     vsfr=(*func)(entity,func_data);
1792
1793     if (debug & DEBUG_CFGEVAL_FLAG)
1794         report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1795                 PA_VSFR(vsfr));
1796
1797     if (vsfr != VSFR_CONTINUE) {
1798         if (debug & DEBUG_CFGEVAL_FLAG)
1799             report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1800         return (vsfr);
1801     }
1802     if (!recurse ) {
1803         if (debug & DEBUG_CFGEVAL_FLAG)
1804             report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1805         return (VSFR_STOP);
1806     }
1807
1808     value_scan_begin(entity);
1809     membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1810     if (!membership_node) {
1811         if (debug & DEBUG_CFGEVAL_FLAG)
1812             report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1813         return (VSFR_CONTINUE);         /* no parent entities */
1814     }
1815
1816     while (1) {
1817         struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1818
1819         if (debug & DEBUG_CFGEVAL_FLAG)
1820             report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1821                     PA_MEMBERSHIP(membership));
1822
1823         entity = value_scan_forward(membership);
1824         if (entity) {
1825             if (debug & DEBUG_CFGEVAL_FLAG)
1826                 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1827                         PA_ENTITY(entity));
1828
1829             vsfr=(*func)(entity,func_data);
1830
1831             if (debug & DEBUG_CFGEVAL_FLAG)
1832                 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1833                         PA_ENTITY(entity), PA_VSFR(vsfr));
1834
1835             if (vsfr == VSFR_FOUND) {
1836                 if (debug & DEBUG_CFGEVAL_FLAG)
1837                     report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1838                 return (vsfr);
1839             }
1840             if (vsfr == VSFR_CONTINUE)
1841                 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1842         }
1843         if (!entity || vsfr == VSFR_STOP) {
1844             ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1845
1846             entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);    /* for retreat from the LAST membership */
1847
1848             if (debug & DEBUG_CFGEVAL_FLAG)
1849                 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1850                         PA_ENTITY(parent_entity), PA_ENTITY(entity));
1851
1852             membership_node = tac_list_node_next(&membership->child_node);
1853         }
1854
1855         while (!membership_node) {
1856             membership = value_scan_backward(entity);
1857             if (!membership) {
1858                 if (debug & DEBUG_CFGEVAL_FLAG)
1859                     report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1860                 return (VSFR_CONTINUE);         /* FINISH */
1861             }
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: backward retreat ('next' chase) "
1867                                 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1868                                 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1869
1870             membership_node = tac_list_node_next(&membership->child_node);
1871         }
1872     }
1873     /* NOTREACHED */
1874 }