Initial import from FreeBSD RELENG_4:
[games.git] / contrib / isc-dhcp / common / execute.c
1 /* execute.c
2
3    Support for executable statements. */
4
5 /*
6  * Copyright (c) 1998-2002 Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The Internet Software Consortium nor the names
19  *    of its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * This software has been written for the Internet Software Consortium
37  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38  * To learn more about the Internet Software Consortium, see
39  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
40  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
41  * ``http://www.nominum.com''.
42  */
43
44 #ifndef lint
45 static char copyright[] =
46 "$Id: execute.c,v 1.44.2.9 2002/11/17 02:26:58 dhankins Exp $ Copyright (c) 1998-2002 The Internet Software Consortium.  All rights reserved.\n";
47 #endif /* not lint */
48
49 #include "dhcpd.h"
50 #include <omapip/omapip_p.h>
51
52 int execute_statements (result, packet, lease, client_state,
53                         in_options, out_options, scope, statements)
54         struct binding_value **result;
55         struct packet *packet;
56         struct lease *lease;
57         struct client_state *client_state;
58         struct option_state *in_options;
59         struct option_state *out_options;
60         struct binding_scope **scope;
61         struct executable_statement *statements;
62 {
63         struct executable_statement *r, *e, *next;
64         int rc;
65         int status;
66         unsigned long num;
67         struct binding_scope *outer;
68         struct binding *binding;
69         struct data_string ds;
70         struct binding_scope *ns;
71
72         if (!statements)
73                 return 1;
74
75         r = (struct executable_statement *)0;
76         next = (struct executable_statement *)0;
77         e = (struct executable_statement *)0;
78         executable_statement_reference (&r, statements, MDL);
79         while (r && !(result && *result)) {
80                 if (r -> next)
81                         executable_statement_reference (&next, r -> next, MDL);
82                 switch (r -> op) {
83                       case statements_statement:
84 #if defined (DEBUG_EXPRESSIONS)
85                         log_debug ("exec: statements");
86 #endif
87                         status = execute_statements (result, packet, lease,
88                                                      client_state, in_options,
89                                                      out_options, scope,
90                                                      r -> data.statements);
91 #if defined (DEBUG_EXPRESSIONS)
92                         log_debug ("exec: statements returns %d", status);
93 #endif
94                         if (!status)
95                                 return 0;
96                         break;
97
98                       case on_statement:
99                         if (lease) {
100                             if (r -> data.on.evtypes & ON_EXPIRY) {
101 #if defined (DEBUG_EXPRESSIONS)
102                                     log_debug ("exec: on expiry");
103 #endif
104                                 if (lease -> on_expiry)
105                                         executable_statement_dereference
106                                                 (&lease -> on_expiry, MDL);
107                                 if (r -> data.on.statements)
108                                         executable_statement_reference
109                                                 (&lease -> on_expiry,
110                                                  r -> data.on.statements, MDL);
111                             }
112                             if (r -> data.on.evtypes & ON_RELEASE) {
113 #if defined (DEBUG_EXPRESSIONS)
114                                     log_debug ("exec: on release");
115 #endif
116                                 if (lease -> on_release)
117                                         executable_statement_dereference
118                                                 (&lease -> on_release, MDL);
119                                 if (r -> data.on.statements)
120                                         executable_statement_reference
121                                                 (&lease -> on_release,
122                                                  r -> data.on.statements, MDL);
123                             }
124                             if (r -> data.on.evtypes & ON_COMMIT) {
125 #if defined (DEBUG_EXPRESSIONS)
126                                     log_debug ("exec: on commit");
127 #endif
128                                 if (lease -> on_commit)
129                                         executable_statement_dereference
130                                                 (&lease -> on_commit, MDL);
131                                 if (r -> data.on.statements)
132                                         executable_statement_reference
133                                                 (&lease -> on_commit,
134                                                  r -> data.on.statements, MDL);
135                             }
136                         }
137                         break;
138
139                       case switch_statement:
140 #if defined (DEBUG_EXPRESSIONS)
141                         log_debug ("exec: switch");
142 #endif
143                         status = (find_matching_case
144                                   (&e, packet, lease, client_state,
145                                    in_options, out_options, scope,
146                                    r -> data.s_switch.expr,
147                                    r -> data.s_switch.statements));
148 #if defined (DEBUG_EXPRESSIONS)
149                         log_debug ("exec: switch: case %lx", (unsigned long)e);
150 #endif
151                         if (status) {
152                                 if (!(execute_statements
153                                       (result, packet, lease, client_state,
154                                        in_options, out_options, scope, e))) {
155                                         executable_statement_dereference
156                                                 (&e, MDL);
157                                         return 0;
158                                 }
159                                 executable_statement_dereference (&e, MDL);
160                         }
161                         break;
162
163                         /* These have no effect when executed. */
164                       case case_statement:
165                       case default_statement:
166                         break;
167
168                       case if_statement:
169                         status = (evaluate_boolean_expression
170                                   (&rc, packet,
171                                    lease, client_state, in_options,
172                                    out_options, scope, r -> data.ie.expr));
173                         
174 #if defined (DEBUG_EXPRESSIONS)
175                         log_debug ("exec: if %s", (status
176                                               ? (rc ? "true" : "false")
177                                               : "NULL"));
178 #endif
179                         /* XXX Treat NULL as false */
180                         if (!status)
181                                 rc = 0;
182                         if (!execute_statements
183                             (result, packet, lease, client_state,
184                              in_options, out_options, scope,
185                              rc ? r -> data.ie.tc : r -> data.ie.fc))
186                                 return 0;
187                         break;
188
189                       case eval_statement:
190                         status = evaluate_expression
191                                 ((struct binding_value **)0,
192                                  packet, lease, client_state, in_options,
193                                  out_options, scope, r -> data.eval, MDL);
194 #if defined (DEBUG_EXPRESSIONS)
195                         log_debug ("exec: evaluate: %s",
196                                    (status ? "succeeded" : "failed"));
197 #endif
198                         break;
199
200                       case return_statement:
201                         status = evaluate_expression
202                                 (result, packet,
203                                  lease, client_state, in_options,
204                                  out_options, scope, r -> data.retval, MDL);
205 #if defined (DEBUG_EXPRESSIONS)
206                         log_debug ("exec: return: %s",
207                                    (status ? "succeeded" : "failed"));
208 #endif
209                         break;
210
211                       case add_statement:
212 #if defined (DEBUG_EXPRESSIONS)
213                         log_debug ("exec: add %s", (r -> data.add -> name
214                                                ? r -> data.add -> name
215                                                : "<unnamed class>"));
216 #endif
217                         classify (packet, r -> data.add);
218                         break;
219
220                       case break_statement:
221 #if defined (DEBUG_EXPRESSIONS)
222                         log_debug ("exec: break");
223 #endif
224                         return 1;
225
226                       case supersede_option_statement:
227                       case send_option_statement:
228 #if defined (DEBUG_EXPRESSIONS)
229                         log_debug ("exec: %s option %s.%s",
230                               (r -> op == supersede_option_statement
231                                ? "supersede" : "send"),
232                               r -> data.option -> option -> universe -> name,
233                               r -> data.option -> option -> name);
234                         goto option_statement;
235 #endif
236                       case default_option_statement:
237 #if defined (DEBUG_EXPRESSIONS)
238                         log_debug ("exec: default option %s.%s",
239                               r -> data.option -> option -> universe -> name,
240                               r -> data.option -> option -> name);
241                         goto option_statement;
242 #endif
243                       case append_option_statement:
244 #if defined (DEBUG_EXPRESSIONS)
245                         log_debug ("exec: append option %s.%s",
246                               r -> data.option -> option -> universe -> name,
247                               r -> data.option -> option -> name);
248                         goto option_statement;
249 #endif
250                       case prepend_option_statement:
251 #if defined (DEBUG_EXPRESSIONS)
252                         log_debug ("exec: prepend option %s.%s",
253                               r -> data.option -> option -> universe -> name,
254                               r -> data.option -> option -> name);
255                       option_statement:
256 #endif
257                         set_option (r -> data.option -> option -> universe,
258                                     out_options, r -> data.option, r -> op);
259                         break;
260
261                       case set_statement:
262                       case define_statement:
263                         if (!scope) {
264                                 log_error ("set %s: no scope",
265                                            r -> data.set.name);
266                                 status = 0;
267                                 break;
268                         }
269                         if (!*scope) {
270                             if (!binding_scope_allocate (scope, MDL)) {
271                                 log_error ("set %s: can't allocate scope",
272                                            r -> data.set.name);
273                                 status = 0;
274                                 break;
275                             }
276                         }
277                         binding = find_binding (*scope, r -> data.set.name);
278 #if defined (DEBUG_EXPRESSIONS)
279                         log_debug ("exec: set %s", r -> data.set.name);
280 #endif
281                         if (!binding) {
282                                 binding = dmalloc (sizeof *binding, MDL);
283                                 if (binding) {
284                                     memset (binding, 0, sizeof *binding);
285                                     binding -> name =
286                                             dmalloc (strlen
287                                                      (r -> data.set.name) + 1,
288                                                      MDL);
289                                     if (binding -> name) {
290                                         strcpy (binding -> name,
291                                                 r -> data.set.name);
292                                         binding -> next = (*scope) -> bindings;
293                                         (*scope) -> bindings = binding;
294                                     } else {
295                                        badalloc:
296                                         dfree (binding, MDL);
297                                         binding = (struct binding *)0;
298                                     }
299                                 }
300                         }
301                         if (binding) {
302                                 if (binding -> value)
303                                         binding_value_dereference
304                                                 (&binding -> value, MDL);
305                                 if (r -> op == set_statement) {
306                                         status = (evaluate_expression
307                                                   (&binding -> value, packet,
308                                                    lease, client_state,
309                                                    in_options, out_options,
310                                                    scope, r -> data.set.expr,
311                                                    MDL));
312                                 } else {
313                                     if (!(binding_value_allocate
314                                           (&binding -> value, MDL))) {
315                                             dfree (binding, MDL);
316                                             binding = (struct binding *)0;
317                                     }
318                                     if (binding -> value) {
319                                         binding -> value -> type =
320                                                 binding_function;
321                                         (fundef_reference
322                                          (&binding -> value -> value.fundef,
323                                           r -> data.set.expr -> data.func,
324                                           MDL));
325                                     }
326                                 }
327                         }
328 #if defined (DEBUG_EXPRESSIONS)
329                         log_debug ("exec: set %s%s", r -> data.set.name,
330                                    (binding && status ? "" : " (failed)"));
331 #endif
332                         break;
333
334                       case unset_statement:
335                         if (!scope || !*scope) {
336                                 status = 0;
337                                 break;
338                         }
339                         binding = find_binding (*scope, r -> data.unset);
340                         if (binding) {
341                                 if (binding -> value)
342                                         binding_value_dereference
343                                                 (&binding -> value, MDL);
344                                 status = 1;
345                         } else
346                                 status = 0;
347 #if defined (DEBUG_EXPRESSIONS)
348                         log_debug ("exec: unset %s: %s", r -> data.unset,
349                                    (status ? "found" : "not found"));
350 #endif
351                         break;
352
353                       case let_statement:
354 #if defined (DEBUG_EXPRESSIONS)
355                         log_debug ("exec: let %s", r -> data.let.name);
356 #endif
357                         ns = (struct binding_scope *)0;
358                         binding_scope_allocate (&ns, MDL);
359                         e = r;
360
361                       next_let:
362                         if (ns) {
363                                 binding = dmalloc (sizeof *binding, MDL);
364                                 memset (binding, 0, sizeof *binding);
365                                 if (!binding) {
366                                    blb:
367                                     binding_scope_dereference (&ns, MDL);
368                                 } else {
369                                     binding -> name =
370                                             dmalloc (strlen
371                                                      (e -> data.let.name + 1),
372                                                      MDL);
373                                     if (binding -> name)
374                                         strcpy (binding -> name,
375                                                 e -> data.let.name);
376                                     else {
377                                         dfree (binding, MDL);
378                                         binding = (struct binding *)0;
379                                         goto blb;
380                                     }
381                                 }
382                         }
383                         if (ns && binding) {
384                                 status = (evaluate_expression
385                                           (&binding -> value, packet, lease,
386                                            client_state,
387                                            in_options, out_options,
388                                            scope, e -> data.set.expr, MDL));
389                                 binding -> next = ns -> bindings;
390                                 ns -> bindings = binding;
391                         }
392
393 #if defined (DEBUG_EXPRESSIONS)
394                         log_debug ("exec: let %s%s", e -> data.let.name,
395                                    (binding && status ? "" : "failed"));
396 #endif
397                         if (!e -> data.let.statements) {
398                         } else if (e -> data.let.statements -> op ==
399                                    let_statement) {
400                                 e = e -> data.let.statements;
401                                 goto next_let;
402                         } else if (ns) {
403                                 if (scope && *scope)
404                                         binding_scope_reference (&ns -> outer,
405                                                                  *scope, MDL);
406                                 execute_statements
407                                       (result, packet, lease,
408                                        client_state,
409                                        in_options, out_options,
410                                        &ns, e -> data.let.statements);
411                         }
412                         if (ns)
413                                 binding_scope_dereference (&ns, MDL);
414                         break;
415
416                       case log_statement:
417                         memset (&ds, 0, sizeof ds);
418                         status = (evaluate_data_expression
419                                   (&ds, packet,
420                                    lease, client_state, in_options,
421                                    out_options, scope, r -> data.log.expr,
422                                    MDL));
423                         
424 #if defined (DEBUG_EXPRESSIONS)
425                         log_debug ("exec: log");
426 #endif
427
428                         if (status) {
429                                 switch (r -> data.log.priority) {
430                                 case log_priority_fatal:
431                                         log_fatal ("%.*s", (int)ds.len,
432                                                    ds.buffer -> data);
433                                         break;
434                                 case log_priority_error:
435                                         log_error ("%.*s", (int)ds.len,
436                                                    ds.buffer -> data);
437                                         break;
438                                 case log_priority_debug:
439                                         log_debug ("%.*s", (int)ds.len,
440                                                    ds.buffer -> data);
441                                         break;
442                                 case log_priority_info:
443                                         log_info ("%.*s", (int)ds.len,
444                                                   ds.buffer -> data);
445                                         break;
446                                 }
447                                 data_string_forget (&ds, MDL);
448                         }
449
450                         break;
451
452                       default:
453                         log_error ("bogus statement type %d", r -> op);
454                         break;
455                 }
456                 executable_statement_dereference (&r, MDL);
457                 if (next) {
458                         executable_statement_reference (&r, next, MDL);
459                         executable_statement_dereference (&next, MDL);
460                 }
461         }
462
463         return 1;
464 }
465
466 /* Execute all the statements in a particular scope, and all statements in
467    scopes outer from that scope, but if a particular limiting scope is
468    reached, do not execute statements in that scope or in scopes outer
469    from it.   More specific scopes need to take precedence over less
470    specific scopes, so we recursively traverse the scope list, executing
471    the most outer scope first. */
472
473 void execute_statements_in_scope (result, packet,
474                                   lease, client_state, in_options, out_options,
475                                   scope, group, limiting_group)
476         struct binding_value **result;
477         struct packet *packet;
478         struct lease *lease;
479         struct client_state *client_state;
480         struct option_state *in_options;
481         struct option_state *out_options;
482         struct binding_scope **scope;
483         struct group *group;
484         struct group *limiting_group;
485 {
486         struct group *limit;
487
488         /* If we've recursed as far as we can, return. */
489         if (!group)
490                 return;
491
492         /* As soon as we get to a scope that is outer than the limiting
493            scope, we are done.   This is so that if somebody does something
494            like this, it does the expected thing:
495
496                 domain-name "fugue.com";
497                 shared-network FOO {
498                         host bar {
499                                 domain-name "othello.fugue.com";
500                                 fixed-address 10.20.30.40;
501                         }
502                         subnet 10.20.30.0 netmask 255.255.255.0 {
503                                 domain-name "manhattan.fugue.com";
504                         }
505                 }
506
507            The problem with the above arrangement is that the host's
508            group nesting will be host -> shared-network -> top-level,
509            and the limiting scope when we evaluate the host's scope
510            will be the subnet -> shared-network -> top-level, so we need
511            to know when we evaluate the host's scope to stop before we
512            evaluate the shared-networks scope, because it's outer than
513            the limiting scope, which means we've already evaluated it. */
514
515         for (limit = limiting_group; limit; limit = limit -> next) {
516                 if (group == limit)
517                         return;
518         }
519
520         if (group -> next)
521                 execute_statements_in_scope (result, packet,
522                                              lease, client_state,
523                                              in_options, out_options, scope,
524                                              group -> next, limiting_group);
525         execute_statements (result, packet, lease, client_state, in_options,
526                             out_options, scope, group -> statements);
527 }
528
529 /* Dereference or free any subexpressions of a statement being freed. */
530
531 int executable_statement_dereference (ptr, file, line)
532         struct executable_statement **ptr;
533         const char *file;
534         int line;
535 {
536         struct executable_statement *bp;
537
538         if (!ptr || !*ptr) {
539                 log_error ("%s(%d): null pointer", file, line);
540 #if defined (POINTER_DEBUG)
541                 abort ();
542 #else
543                 return 0;
544 #endif
545         }
546
547         (*ptr) -> refcnt--;
548         rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
549         if ((*ptr) -> refcnt > 0) {
550                 *ptr = (struct executable_statement *)0;
551                 return 1;
552         }
553
554         if ((*ptr) -> refcnt < 0) {
555                 log_error ("%s(%d): negative refcnt!", file, line);
556 #if defined (DEBUG_RC_HISTORY)
557                 dump_rc_history (*ptr);
558 #endif
559 #if defined (POINTER_DEBUG)
560                 abort ();
561 #else
562                 return 0;
563 #endif
564         }
565
566         if ((*ptr) -> next)
567                 executable_statement_dereference (&(*ptr) -> next, file, line);
568
569         switch ((*ptr) -> op) {
570               case statements_statement:
571                 if ((*ptr) -> data.statements)
572                         executable_statement_dereference
573                                 (&(*ptr) -> data.statements, file, line);
574                 break;
575
576               case on_statement:
577                 if ((*ptr) -> data.on.statements)
578                         executable_statement_dereference
579                                 (&(*ptr) -> data.on.statements, file, line);
580                 break;
581
582               case switch_statement:
583                 if ((*ptr) -> data.s_switch.statements)
584                         executable_statement_dereference
585                                 (&(*ptr) -> data.on.statements, file, line);
586                 if ((*ptr) -> data.s_switch.expr)
587                         expression_dereference (&(*ptr) -> data.s_switch.expr,
588                                                 file, line);
589                 break;
590
591               case case_statement:
592                 if ((*ptr) -> data.s_switch.expr)
593                         expression_dereference (&(*ptr) -> data.c_case,
594                                                 file, line);
595                 break;
596
597               case if_statement:
598                 if ((*ptr) -> data.ie.expr)
599                         expression_dereference (&(*ptr) -> data.ie.expr,
600                                                 file, line);
601                 if ((*ptr) -> data.ie.tc)
602                         executable_statement_dereference
603                                 (&(*ptr) -> data.ie.tc, file, line);
604                 if ((*ptr) -> data.ie.fc)
605                         executable_statement_dereference
606                                 (&(*ptr) -> data.ie.fc, file, line);
607                 break;
608
609               case eval_statement:
610                 if ((*ptr) -> data.eval)
611                         expression_dereference (&(*ptr) -> data.eval,
612                                                 file, line);
613                 break;
614
615               case return_statement:
616                 if ((*ptr) -> data.eval)
617                         expression_dereference (&(*ptr) -> data.eval,
618                                                 file, line);
619                 break;
620
621               case set_statement:
622                 if ((*ptr)->data.set.name)
623                         dfree ((*ptr)->data.set.name, file, line);
624                 if ((*ptr)->data.set.expr)
625                         expression_dereference (&(*ptr) -> data.set.expr,
626                                                 file, line);
627                 break;
628
629               case unset_statement:
630                 if ((*ptr)->data.unset)
631                         dfree ((*ptr)->data.unset, file, line);
632                 break;
633
634               case supersede_option_statement:
635               case send_option_statement:
636               case default_option_statement:
637               case append_option_statement:
638               case prepend_option_statement:
639                 if ((*ptr) -> data.option)
640                         option_cache_dereference (&(*ptr) -> data.option,
641                                                   file, line);
642                 break;
643
644               default:
645                 /* Nothing to do. */
646                 break;
647         }
648
649         dfree ((*ptr), file, line);
650         *ptr = (struct executable_statement *)0;
651         return 1;
652 }
653
654 void write_statements (file, statements, indent)
655         FILE *file;
656         struct executable_statement *statements;
657         int indent;
658 {
659         struct executable_statement *r, *x;
660         int result;
661         int status;
662         const char *s, *t, *dot;
663         int col;
664
665         if (!statements)
666                 return;
667
668         for (r = statements; r; r = r -> next) {
669                 switch (r -> op) {
670                       case statements_statement:
671                         write_statements (file, r -> data.statements, indent);
672                         break;
673
674                       case on_statement:
675                         indent_spaces (file, indent);
676                         fprintf (file, "on ");
677                         s = "";
678                         if (r -> data.on.evtypes & ON_EXPIRY) {
679                                 fprintf (file, "%sexpiry", s);
680                                 s = " or ";
681                         }
682                         if (r -> data.on.evtypes & ON_COMMIT) {
683                                 fprintf (file, "%scommit", s);
684                                 s = "or";
685                         }
686                         if (r -> data.on.evtypes & ON_RELEASE) {
687                                 fprintf (file, "%srelease", s);
688                                 s = "or";
689                         }
690                         if (r -> data.on.statements) {
691                                 fprintf (file, " {");
692                                 write_statements (file,
693                                                   r -> data.on.statements,
694                                                   indent + 2);
695                                 indent_spaces (file, indent);
696                                 fprintf (file, "}");
697                         } else {
698                                 fprintf (file, ";");
699                         }
700                         break;
701
702                       case switch_statement:
703                         indent_spaces (file, indent);
704                         fprintf (file, "switch (");
705                         col = write_expression (file,
706                                                 r -> data.s_switch.expr,
707                                                 indent + 7, indent + 7, 1);
708                         col = token_print_indent (file, col, indent + 7,
709                                                   "", "", ")");
710                         token_print_indent (file,
711                                             col, indent, " ", "", "{");
712                         write_statements (file, r -> data.s_switch.statements,
713                                           indent + 2);
714                         indent_spaces (file, indent);
715                         fprintf (file, "}");
716                         break;
717                         
718                       case case_statement:
719                         indent_spaces (file, indent - 1);
720                         fprintf (file, "case ");
721                         col = write_expression (file,
722                                                 r -> data.s_switch.expr,
723                                                 indent + 5, indent + 5, 1);
724                         token_print_indent (file, col, indent + 5,
725                                             "", "", ":");
726                         break;
727                         
728                       case default_statement:
729                         indent_spaces (file, indent - 1);
730                         fprintf (file, "default: ");
731                         break;
732
733                       case if_statement:
734                         indent_spaces (file, indent);
735                         fprintf (file, "if ");
736                         x = r;
737                         col = write_expression (file,
738                                                 x -> data.ie.expr,
739                                                 indent + 3, indent + 3, 1);
740                       else_if:
741                         token_print_indent (file, col, indent, " ", "", "{");
742                         write_statements (file, x -> data.ie.tc, indent + 2);
743                         if (x -> data.ie.fc &&
744                             x -> data.ie.fc -> op == if_statement &&
745                             !x -> data.ie.fc -> next) {
746                                 indent_spaces (file, indent);
747                                 fprintf (file, "} elsif ");
748                                 x = x -> data.ie.fc;
749                                 col = write_expression (file,
750                                                         x -> data.ie.expr,
751                                                         indent + 6,
752                                                         indent + 6, 1);
753                                 goto else_if;
754                         }
755                         if (x -> data.ie.fc) {
756                                 indent_spaces (file, indent);
757                                 fprintf (file, "} else {");
758                                 write_statements (file, x -> data.ie.fc,
759                                                   indent + 2);
760                         }
761                         indent_spaces (file, indent);
762                         fprintf (file, "}");
763                         break;
764
765                       case eval_statement:
766                         indent_spaces (file, indent);
767                         fprintf (file, "eval ");
768                         col = write_expression (file, r -> data.eval,
769                                                 indent + 5, indent + 5, 1);
770                         fprintf (file, ";");
771                         break;
772
773                       case return_statement:
774                         indent_spaces (file, indent);
775                         fprintf (file, "return;");
776                         break;
777
778                       case add_statement:
779                         indent_spaces (file, indent);
780                         fprintf (file, "add \"%s\"", r -> data.add -> name);
781                         break;
782
783                       case break_statement:
784                         indent_spaces (file, indent);
785                         fprintf (file, "break;");
786                         break;
787
788                       case supersede_option_statement:
789                       case send_option_statement:
790                         s = "supersede";
791                         goto option_statement;
792
793                       case default_option_statement:
794                         s = "default";
795                         goto option_statement;
796
797                       case append_option_statement:
798                         s = "append";
799                         goto option_statement;
800
801                       case prepend_option_statement:
802                         s = "prepend";
803                       option_statement:
804                         /* Note: the reason we don't try to pretty print
805                            the option here is that the format of the option
806                            may change in dhcpd.conf, and then when this
807                            statement was read back, it would cause a syntax
808                            error. */
809                         if (r -> data.option -> option -> universe ==
810                             &dhcp_universe) {
811                                 t = "";
812                                 dot = "";
813                         } else {
814                                 t = (r -> data.option -> option ->
815                                      universe -> name);
816                                 dot = ".";
817                         }
818                         indent_spaces (file, indent);
819                         fprintf (file, "%s %s%s%s = ", s, t, dot,
820                                  r -> data.option -> option -> name);
821                         col = (indent + strlen (s) + strlen (t) +
822                                strlen (dot) + strlen (r -> data.option ->
823                                                       option -> name) + 4);
824                         if (r -> data.option -> expression)
825                                 write_expression
826                                         (file,
827                                          r -> data.option -> expression,
828                                          col, indent + 8, 1);
829                         else
830                                 token_indent_data_string
831                                         (file, col, indent + 8, "", "",
832                                          &r -> data.option -> data);
833                                          
834                         fprintf (file, ";"); /* XXX */
835                         break;
836
837                       case set_statement:
838                         indent_spaces (file, indent);
839                         fprintf (file, "set ");
840                         col = token_print_indent (file, indent + 4, indent + 4,
841                                                   "", "", r -> data.set.name);
842                         col = token_print_indent (file, col, indent + 4,
843                                                   " ", " ", "=");
844                         col = write_expression (file, r -> data.set.expr,
845                                                 indent + 3, indent + 3, 0);
846                         col = token_print_indent (file, col, indent + 4,
847                                                   " ", "", ";");
848                         break;
849                         
850                       case unset_statement:
851                         indent_spaces (file, indent);
852                         fprintf (file, "unset ");
853                         col = token_print_indent (file, indent + 6, indent + 6,
854                                                   "", "", r -> data.set.name);
855                         col = token_print_indent (file, col, indent + 6,
856                                                   " ", "", ";");
857                         break;
858
859                       case log_statement:
860                         indent_spaces (file, indent);
861                         fprintf (file, "log ");
862                         col = token_print_indent (file, col, indent + 4,
863                                                   "", "", "(");
864                         switch (r -> data.log.priority) {
865                         case log_priority_fatal:
866                                 col = token_print_indent
867                                         (file, col, indent + 4, "",
868                                          " ", "fatal,");
869                                 break;
870                         case log_priority_error:
871                                 col = token_print_indent
872                                         (file, col, indent + 4, "",
873                                          " ", "error,");
874                                 break;
875                         case log_priority_debug:
876                                 col = token_print_indent
877                                         (file, col, indent + 4, "",
878                                          " ", "debug,");
879                                 break;
880                         case log_priority_info:
881                                 col = token_print_indent
882                                         (file, col, indent + 4, "",
883                                          " ", "info,");
884                                 break;
885                         }
886                         col = write_expression (file, r -> data.log.expr,
887                                                 indent + 4, indent + 4, 0);
888                         col = token_print_indent (file, col, indent + 4,
889                                                   "", "", ");");
890
891                         break;
892                         
893                       default:
894                         log_fatal ("bogus statement type %d\n", r -> op);
895                 }
896         }
897 }
898
899 /* Find a case statement in the sequence of executable statements that
900    matches the expression, and if found, return the following statement.
901    If no case statement matches, try to find a default statement and
902    return that (the default statement can precede all the case statements).
903    Otherwise, return the null statement. */
904
905 int find_matching_case (struct executable_statement **ep,
906                         struct packet *packet, struct lease *lease,
907                         struct client_state *client_state,
908                         struct option_state *in_options,
909                         struct option_state *out_options,
910                         struct binding_scope **scope,
911                         struct expression *expr,
912                         struct executable_statement *stmt)
913 {
914         int status, sub;
915         struct executable_statement *s;
916         unsigned long foo;
917
918         if (is_data_expression (expr)) {
919                 struct executable_statement *e;
920                 struct data_string cd, ds;
921                 memset (&ds, 0, sizeof ds);
922                 memset (&cd, 0, sizeof cd);
923
924                 status = (evaluate_data_expression (&ds, packet, lease,
925                                                     client_state, in_options,
926                                                     out_options, scope, expr,
927                                                     MDL));
928                 if (status) {
929                     for (s = stmt; s; s = s -> next) {
930                         if (s -> op == case_statement) {
931                                 sub = (evaluate_data_expression
932                                        (&cd, packet, lease, client_state,
933                                         in_options, out_options,
934                                         scope, s -> data.c_case, MDL));
935                                 if (sub && cd.len == ds.len &&
936                                     !memcmp (cd.data, ds.data, cd.len))
937                                 {
938                                         data_string_forget (&cd, MDL);
939                                         data_string_forget (&ds, MDL);
940                                         executable_statement_reference
941                                                 (ep, s -> next, MDL);
942                                         return 1;
943                                 }
944                                 data_string_forget (&cd, MDL);
945                         }
946                     }
947                     data_string_forget (&ds, MDL);
948                 }
949         } else {
950                 unsigned long n, c;
951                 status = evaluate_numeric_expression (&n, packet, lease,
952                                                       client_state,
953                                                       in_options, out_options,
954                                                       scope, expr);
955
956                 if (status) {
957                     for (s = stmt; s; s = s -> next) {
958                         if (s -> op == case_statement) {
959                                 sub = (evaluate_numeric_expression
960                                        (&c, packet, lease, client_state,
961                                         in_options, out_options,
962                                         scope, s -> data.c_case));
963                                 if (sub && n == c) {
964                                         executable_statement_reference
965                                                 (ep, s -> next, MDL);
966                                         return 1;
967                                 }
968                         }
969                     }
970                 }
971         }
972
973         /* If we didn't find a matching case statement, look for a default
974            statement and return the statement following it. */
975         for (s = stmt; s; s = s -> next)
976                 if (s -> op == default_statement)
977                         break;
978         if (s) {
979                 executable_statement_reference (ep, s -> next, MDL);
980                 return 1;
981         }
982         return 0;
983 }
984
985 int executable_statement_foreach (struct executable_statement *stmt,
986                                   int (*callback) (struct
987                                                    executable_statement *,
988                                                    void *, int),
989                                   void *vp, int condp)
990 {
991         struct executable_statement *foo;
992         int ok = 0;
993         int result;
994
995         for (foo = stmt; foo; foo = foo -> next) {
996             if ((*callback) (foo, vp, condp) != 0)
997                 ok = 1;
998             switch (foo -> op) {
999               case null_statement:
1000                 break;
1001               case if_statement:
1002                 if (executable_statement_foreach (foo -> data.ie.tc,
1003                                                   callback, vp, 1))
1004                         ok = 1;
1005                 if (executable_statement_foreach (foo -> data.ie.fc,
1006                                                   callback, vp, 1))
1007                         ok = 1;
1008                 break;
1009               case add_statement:
1010                 break;
1011               case eval_statement:
1012                 break;
1013               case break_statement:
1014                 break;
1015               case default_option_statement:
1016                 break;
1017               case supersede_option_statement:
1018                 break;
1019               case append_option_statement:
1020                 break;
1021               case prepend_option_statement:
1022                 break;
1023               case send_option_statement:
1024                 break;
1025               case statements_statement:
1026                 if ((executable_statement_foreach
1027                      (foo -> data.statements, callback, vp, condp)))
1028                         ok = 1;
1029                 break;
1030               case on_statement:
1031                 if ((executable_statement_foreach
1032                      (foo -> data.on.statements, callback, vp, 1)))
1033                         ok = 1;
1034                 break;
1035               case switch_statement:
1036                 if ((executable_statement_foreach
1037                      (foo -> data.s_switch.statements, callback, vp, 1)))
1038                         ok = 1;
1039                 break;
1040               case case_statement:
1041                 break;
1042               case default_statement:
1043                 break;
1044               case set_statement:
1045                 break;
1046               case unset_statement:
1047                 break;
1048               case let_statement:
1049                 if ((executable_statement_foreach
1050                      (foo -> data.let.statements, callback, vp, 0)))
1051                         ok = 1;
1052                 break;
1053               case define_statement:
1054                 break;
1055               case log_statement:
1056               case return_statement:
1057                 break;
1058             }
1059         }
1060         return ok;
1061 }