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