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