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