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