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