00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "dhcpd.h"
00031 #include <omapip/omapip_p.h>
00032 #include <sys/types.h>
00033 #include <sys/wait.h>
00034
00035 int execute_statements (result, packet, lease, client_state,
00036 in_options, out_options, scope, statements,
00037 on_star)
00038 struct binding_value **result;
00039 struct packet *packet;
00040 struct lease *lease;
00041 struct client_state *client_state;
00042 struct option_state *in_options;
00043 struct option_state *out_options;
00044 struct binding_scope **scope;
00045 struct executable_statement *statements;
00046 struct on_star *on_star;
00047 {
00048 struct executable_statement *r, *e, *next;
00049 int rc;
00050 int status;
00051 struct binding *binding;
00052 struct data_string ds;
00053 struct binding_scope *ns;
00054
00055 if (!statements)
00056 return 1;
00057
00058 r = NULL;
00059 next = NULL;
00060 e = NULL;
00061 executable_statement_reference (&r, statements, MDL);
00062 while (r && !(result && *result)) {
00063 if (r->next)
00064 executable_statement_reference (&next, r->next, MDL);
00065 switch (r->op) {
00066 case statements_statement:
00067 #if defined (DEBUG_EXPRESSIONS)
00068 log_debug ("exec: statements");
00069 #endif
00070 status = execute_statements (result, packet, lease,
00071 client_state, in_options,
00072 out_options, scope,
00073 r->data.statements,
00074 on_star);
00075 #if defined (DEBUG_EXPRESSIONS)
00076 log_debug ("exec: statements returns %d", status);
00077 #endif
00078 if (!status)
00079 return 0;
00080 break;
00081
00082 case on_statement:
00083
00084
00085
00086
00087
00088 if ((on_star == NULL) && (lease != NULL))
00089 on_star = &lease->on_star;
00090
00091 if (on_star != NULL) {
00092 if (r->data.on.evtypes & ON_EXPIRY) {
00093 #if defined (DEBUG_EXPRESSIONS)
00094 log_debug ("exec: on expiry");
00095 #endif
00096 if (on_star->on_expiry)
00097 executable_statement_dereference
00098 (&on_star->on_expiry, MDL);
00099 if (r->data.on.statements)
00100 executable_statement_reference
00101 (&on_star->on_expiry,
00102 r->data.on.statements, MDL);
00103 }
00104 if (r->data.on.evtypes & ON_RELEASE) {
00105 #if defined (DEBUG_EXPRESSIONS)
00106 log_debug ("exec: on release");
00107 #endif
00108 if (on_star->on_release)
00109 executable_statement_dereference
00110 (&on_star->on_release, MDL);
00111 if (r->data.on.statements)
00112 executable_statement_reference
00113 (&on_star->on_release,
00114 r->data.on.statements, MDL);
00115 }
00116 if (r->data.on.evtypes & ON_COMMIT) {
00117 #if defined (DEBUG_EXPRESSIONS)
00118 log_debug ("exec: on commit");
00119 #endif
00120 if (on_star->on_commit)
00121 executable_statement_dereference
00122 (&on_star->on_commit, MDL);
00123 if (r->data.on.statements)
00124 executable_statement_reference
00125 (&on_star->on_commit,
00126 r->data.on.statements, MDL);
00127 }
00128 }
00129 break;
00130
00131 case switch_statement:
00132 #if defined (DEBUG_EXPRESSIONS)
00133 log_debug ("exec: switch");
00134 #endif
00135 status = (find_matching_case
00136 (&e, packet, lease, client_state,
00137 in_options, out_options, scope,
00138 r->data.s_switch.expr,
00139 r->data.s_switch.statements));
00140 #if defined (DEBUG_EXPRESSIONS)
00141 log_debug ("exec: switch: case %lx", (unsigned long)e);
00142 #endif
00143 if (status) {
00144 if (!(execute_statements
00145 (result, packet, lease, client_state,
00146 in_options, out_options, scope, e,
00147 on_star))) {
00148 executable_statement_dereference
00149 (&e, MDL);
00150 return 0;
00151 }
00152 executable_statement_dereference (&e, MDL);
00153 }
00154 break;
00155
00156
00157 case case_statement:
00158 case default_statement:
00159 break;
00160
00161 case if_statement:
00162 status = (evaluate_boolean_expression
00163 (&rc, packet,
00164 lease, client_state, in_options,
00165 out_options, scope, r->data.ie.expr));
00166
00167 #if defined (DEBUG_EXPRESSIONS)
00168 log_debug ("exec: if %s", (status
00169 ? (rc ? "true" : "false")
00170 : "NULL"));
00171 #endif
00172
00173 if (!status)
00174 rc = 0;
00175 if (!execute_statements
00176 (result, packet, lease, client_state,
00177 in_options, out_options, scope,
00178 rc ? r->data.ie.tc : r->data.ie.fc,
00179 on_star))
00180 return 0;
00181 break;
00182
00183 case eval_statement:
00184 status = evaluate_expression
00185 (NULL, packet, lease, client_state, in_options,
00186 out_options, scope, r->data.eval, MDL);
00187 #if defined (DEBUG_EXPRESSIONS)
00188 log_debug ("exec: evaluate: %s",
00189 (status ? "succeeded" : "failed"));
00190 #else
00191 POST(status);
00192 #endif
00193 break;
00194
00195 case execute_statement: {
00196 #ifdef ENABLE_EXECUTE
00197 struct expression *expr;
00198 char **argv;
00199 int i, argc = r->data.execute.argc;
00200 pid_t p;
00201
00202
00203 argv = dmalloc((argc + 2) * sizeof(*argv), MDL);
00204 if (!argv)
00205 break;
00206
00207 argv[0] = dmalloc(strlen(r->data.execute.command) + 1,
00208 MDL);
00209 if (argv[0]) {
00210 strcpy(argv[0], r->data.execute.command);
00211 } else {
00212 goto execute_out;
00213 }
00214
00215 log_debug("execute_statement argv[0] = %s", argv[0]);
00216
00217 for (i = 1, expr = r->data.execute.arglist; expr;
00218 expr = expr->data.arg.next, i++) {
00219 memset (&ds, 0, sizeof(ds));
00220 status = (evaluate_data_expression
00221 (&ds, packet,
00222 lease, client_state, in_options,
00223 out_options, scope,
00224 expr->data.arg.val, MDL));
00225 if (status) {
00226 argv[i] = dmalloc(ds.len + 1, MDL);
00227 if (argv[i]) {
00228 memcpy(argv[i], ds.data,
00229 ds.len);
00230 argv[i][ds.len] = 0;
00231 log_debug("execute_statement argv[%d] = %s", i, argv[i]);
00232 }
00233 data_string_forget (&ds, MDL);
00234 if (!argv[i]) {
00235 log_debug("execute_statement failed argv[%d]", i);
00236 goto execute_out;
00237 }
00238 } else {
00239 log_debug("execute: bad arg %d", i);
00240 goto execute_out;
00241 }
00242 }
00243 argv[i] = NULL;
00244
00245 if ((p = fork()) > 0) {
00246 int status;
00247 waitpid(p, &status, 0);
00248
00249 if (status) {
00250 log_error("execute: %s exit status %d",
00251 argv[0], status);
00252 }
00253 } else if (p == 0) {
00254 execvp(argv[0], argv);
00255 log_error("Unable to execute %s: %m", argv[0]);
00256 _exit(127);
00257 } else {
00258 log_error("execute: fork() failed");
00259 }
00260
00261 execute_out:
00262 for (i = 0; i <= argc; i++) {
00263 if(argv[i])
00264 dfree(argv[i], MDL);
00265 }
00266
00267 dfree(argv, MDL);
00268 #else
00269 log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
00270 "is not defined).", MDL);
00271 #endif
00272 break;
00273 }
00274
00275 case return_statement:
00276 status = evaluate_expression
00277 (result, packet,
00278 lease, client_state, in_options,
00279 out_options, scope, r -> data.retval, MDL);
00280 #if defined (DEBUG_EXPRESSIONS)
00281 log_debug ("exec: return: %s",
00282 (status ? "succeeded" : "failed"));
00283 #else
00284 POST(status);
00285 #endif
00286 break;
00287
00288 case add_statement:
00289 #if defined (DEBUG_EXPRESSIONS)
00290 log_debug ("exec: add %s", (r->data.add->name
00291 ? r->data.add->name
00292 : "<unnamed class>"));
00293 #endif
00294 classify (packet, r->data.add);
00295 break;
00296
00297 case break_statement:
00298 #if defined (DEBUG_EXPRESSIONS)
00299 log_debug ("exec: break");
00300 #endif
00301 return 1;
00302
00303 case supersede_option_statement:
00304 case send_option_statement:
00305 #if defined (DEBUG_EXPRESSIONS)
00306 log_debug ("exec: %s option %s.%s",
00307 (r->op == supersede_option_statement
00308 ? "supersede" : "send"),
00309 r->data.option->option->universe->name,
00310 r->data.option->option->name);
00311 goto option_statement;
00312 #endif
00313 case default_option_statement:
00314 #if defined (DEBUG_EXPRESSIONS)
00315 log_debug ("exec: default option %s.%s",
00316 r->data.option->option->universe->name,
00317 r->data.option->option->name);
00318 goto option_statement;
00319 #endif
00320 case append_option_statement:
00321 #if defined (DEBUG_EXPRESSIONS)
00322 log_debug ("exec: append option %s.%s",
00323 r->data.option->option->universe->name,
00324 r->data.option->option->name);
00325 goto option_statement;
00326 #endif
00327 case prepend_option_statement:
00328 #if defined (DEBUG_EXPRESSIONS)
00329 log_debug ("exec: prepend option %s.%s",
00330 r->data.option->option->universe->name,
00331 r->data.option->option->name);
00332 option_statement:
00333 #endif
00334 set_option (r->data.option->option->universe,
00335 out_options, r->data.option, r->op);
00336 break;
00337
00338 case set_statement:
00339 case define_statement:
00340 status = 1;
00341 if (!scope) {
00342 log_error("set %s: no scope",
00343 r->data.set.name);
00344 break;
00345 }
00346 if (!*scope) {
00347 if (!binding_scope_allocate(scope, MDL)) {
00348 log_error("set %s: can't allocate scope",
00349 r->data.set.name);
00350 break;
00351 }
00352 }
00353 binding = find_binding(*scope, r->data.set.name);
00354 #if defined (DEBUG_EXPRESSIONS)
00355 log_debug("exec: set %s", r->data.set.name);
00356 #else
00357 POST(status);
00358 #endif
00359 if (binding == NULL) {
00360 binding = dmalloc(sizeof(*binding), MDL);
00361 if (binding != NULL) {
00362 memset(binding, 0, sizeof(*binding));
00363 binding->name =
00364 dmalloc(strlen
00365 (r->data.set.name) + 1,
00366 MDL);
00367 if (binding->name != NULL) {
00368 strcpy(binding->name, r->data.set.name);
00369 binding->next = (*scope)->bindings;
00370 (*scope)->bindings = binding;
00371 } else {
00372 dfree(binding, MDL);
00373 binding = NULL;
00374 }
00375 }
00376 }
00377 if (binding != NULL) {
00378 if (binding->value != NULL)
00379 binding_value_dereference
00380 (&binding->value, MDL);
00381 if (r->op == set_statement) {
00382 status = (evaluate_expression
00383 (&binding->value, packet,
00384 lease, client_state,
00385 in_options, out_options,
00386 scope, r->data.set.expr,
00387 MDL));
00388 } else {
00389 if (!(binding_value_allocate
00390 (&binding->value, MDL))) {
00391 dfree(binding, MDL);
00392 binding = NULL;
00393 }
00394 if ((binding != NULL) &&
00395 (binding->value != NULL)) {
00396 binding->value->type =
00397 binding_function;
00398 (fundef_reference
00399 (&binding->value->value.fundef,
00400 r->data.set.expr->data.func,
00401 MDL));
00402 }
00403 }
00404 }
00405 #if defined (DEBUG_EXPRESSIONS)
00406 log_debug ("exec: set %s%s", r -> data.set.name,
00407 (binding && status ? "" : " (failed)"));
00408 #else
00409 POST(status);
00410 #endif
00411 break;
00412
00413 case unset_statement:
00414 if (!scope || !*scope)
00415 break;
00416 binding = find_binding (*scope, r->data.unset);
00417 if (binding) {
00418 if (binding->value)
00419 binding_value_dereference
00420 (&binding->value, MDL);
00421 status = 1;
00422 } else
00423 status = 0;
00424 #if defined (DEBUG_EXPRESSIONS)
00425 log_debug ("exec: unset %s: %s", r->data.unset,
00426 (status ? "found" : "not found"));
00427 #else
00428 POST(status);
00429 #endif
00430 break;
00431
00432 case let_statement:
00433 #if defined (DEBUG_EXPRESSIONS)
00434 log_debug("exec: let %s", r->data.let.name);
00435 #endif
00436 status = 0;
00437 ns = NULL;
00438 binding_scope_allocate (&ns, MDL);
00439 e = r;
00440
00441 next_let:
00442 if (ns) {
00443 binding = dmalloc(sizeof(*binding), MDL);
00444 memset(binding, 0, sizeof(*binding));
00445 if (!binding) {
00446 blb:
00447 binding_scope_dereference(&ns, MDL);
00448 } else {
00449 binding->name =
00450 dmalloc(strlen
00451 (e->data.let.name + 1),
00452 MDL);
00453 if (binding->name)
00454 strcpy(binding->name,
00455 e->data.let.name);
00456 else {
00457 dfree(binding, MDL);
00458 binding = NULL;
00459 goto blb;
00460 }
00461 }
00462 } else
00463 binding = NULL;
00464
00465 if (ns && binding) {
00466 status = (evaluate_expression
00467 (&binding->value, packet, lease,
00468 client_state,
00469 in_options, out_options,
00470 scope, e->data.set.expr, MDL));
00471 binding->next = ns->bindings;
00472 ns->bindings = binding;
00473 }
00474
00475 #if defined (DEBUG_EXPRESSIONS)
00476 log_debug("exec: let %s%s", e->data.let.name,
00477 (binding && status ? "" : "failed"));
00478 #else
00479 POST(status);
00480 #endif
00481 if (!e->data.let.statements) {
00482 } else if (e->data.let.statements->op ==
00483 let_statement) {
00484 e = e->data.let.statements;
00485 goto next_let;
00486 } else if (ns) {
00487 if (scope && *scope)
00488 binding_scope_reference(&ns->outer,
00489 *scope, MDL);
00490 execute_statements
00491 (result, packet, lease, client_state,
00492 in_options, out_options,
00493 &ns, e->data.let.statements, on_star);
00494 }
00495 if (ns)
00496 binding_scope_dereference(&ns, MDL);
00497 break;
00498
00499 case log_statement:
00500 memset (&ds, 0, sizeof ds);
00501 status = (evaluate_data_expression
00502 (&ds, packet,
00503 lease, client_state, in_options,
00504 out_options, scope, r->data.log.expr, MDL));
00505
00506 #if defined (DEBUG_EXPRESSIONS)
00507 log_debug ("exec: log");
00508 #endif
00509
00510 if (status) {
00511 switch (r->data.log.priority) {
00512 case log_priority_fatal:
00513 log_fatal ("%.*s", (int)ds.len,
00514 ds.data);
00515 break;
00516 case log_priority_error:
00517 log_error ("%.*s", (int)ds.len,
00518 ds.data);
00519 break;
00520 case log_priority_debug:
00521 log_debug ("%.*s", (int)ds.len,
00522 ds.data);
00523 break;
00524 case log_priority_info:
00525 log_info ("%.*s", (int)ds.len,
00526 ds.data);
00527 break;
00528 }
00529 data_string_forget (&ds, MDL);
00530 }
00531
00532 break;
00533
00534 default:
00535 log_error ("bogus statement type %d", r -> op);
00536 break;
00537 }
00538 executable_statement_dereference (&r, MDL);
00539 if (next) {
00540 executable_statement_reference (&r, next, MDL);
00541 executable_statement_dereference (&next, MDL);
00542 }
00543 }
00544
00545 return 1;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555 void execute_statements_in_scope (result, packet,
00556 lease, client_state, in_options, out_options,
00557 scope, group, limiting_group, on_star)
00558 struct binding_value **result;
00559 struct packet *packet;
00560 struct lease *lease;
00561 struct client_state *client_state;
00562 struct option_state *in_options;
00563 struct option_state *out_options;
00564 struct binding_scope **scope;
00565 struct group *group;
00566 struct group *limiting_group;
00567 struct on_star *on_star;
00568 {
00569 struct group *limit;
00570
00571
00572 if (!group)
00573 return;
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598 for (limit = limiting_group; limit; limit = limit -> next) {
00599 if (group == limit)
00600 return;
00601 }
00602
00603 if (group -> next)
00604 execute_statements_in_scope (result, packet,
00605 lease, client_state,
00606 in_options, out_options, scope,
00607 group->next, limiting_group,
00608 on_star);
00609 execute_statements (result, packet, lease, client_state, in_options,
00610 out_options, scope, group->statements, on_star);
00611 }
00612
00613
00614
00615 int executable_statement_dereference (ptr, file, line)
00616 struct executable_statement **ptr;
00617 const char *file;
00618 int line;
00619 {
00620 if (!ptr || !*ptr) {
00621 log_error ("%s(%d): null pointer", file, line);
00622 #if defined (POINTER_DEBUG)
00623 abort ();
00624 #else
00625 return 0;
00626 #endif
00627 }
00628
00629 (*ptr) -> refcnt--;
00630 rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
00631 if ((*ptr) -> refcnt > 0) {
00632 *ptr = (struct executable_statement *)0;
00633 return 1;
00634 }
00635
00636 if ((*ptr) -> refcnt < 0) {
00637 log_error ("%s(%d): negative refcnt!", file, line);
00638 #if defined (DEBUG_RC_HISTORY)
00639 dump_rc_history (*ptr);
00640 #endif
00641 #if defined (POINTER_DEBUG)
00642 abort ();
00643 #else
00644 return 0;
00645 #endif
00646 }
00647
00648 if ((*ptr) -> next)
00649 executable_statement_dereference (&(*ptr) -> next, file, line);
00650
00651 switch ((*ptr) -> op) {
00652 case statements_statement:
00653 if ((*ptr) -> data.statements)
00654 executable_statement_dereference
00655 (&(*ptr) -> data.statements, file, line);
00656 break;
00657
00658 case on_statement:
00659 if ((*ptr) -> data.on.statements)
00660 executable_statement_dereference
00661 (&(*ptr) -> data.on.statements, file, line);
00662 break;
00663
00664 case switch_statement:
00665 if ((*ptr) -> data.s_switch.statements)
00666 executable_statement_dereference
00667 (&(*ptr) -> data.on.statements, file, line);
00668 if ((*ptr) -> data.s_switch.expr)
00669 expression_dereference (&(*ptr) -> data.s_switch.expr,
00670 file, line);
00671 break;
00672
00673 case case_statement:
00674 if ((*ptr) -> data.s_switch.expr)
00675 expression_dereference (&(*ptr) -> data.c_case,
00676 file, line);
00677 break;
00678
00679 case if_statement:
00680 if ((*ptr) -> data.ie.expr)
00681 expression_dereference (&(*ptr) -> data.ie.expr,
00682 file, line);
00683 if ((*ptr) -> data.ie.tc)
00684 executable_statement_dereference
00685 (&(*ptr) -> data.ie.tc, file, line);
00686 if ((*ptr) -> data.ie.fc)
00687 executable_statement_dereference
00688 (&(*ptr) -> data.ie.fc, file, line);
00689 break;
00690
00691 case eval_statement:
00692 if ((*ptr) -> data.eval)
00693 expression_dereference (&(*ptr) -> data.eval,
00694 file, line);
00695 break;
00696
00697 case return_statement:
00698 if ((*ptr) -> data.eval)
00699 expression_dereference (&(*ptr) -> data.eval,
00700 file, line);
00701 break;
00702
00703 case set_statement:
00704 if ((*ptr)->data.set.name)
00705 dfree ((*ptr)->data.set.name, file, line);
00706 if ((*ptr)->data.set.expr)
00707 expression_dereference (&(*ptr) -> data.set.expr,
00708 file, line);
00709 break;
00710
00711 case unset_statement:
00712 if ((*ptr)->data.unset)
00713 dfree ((*ptr)->data.unset, file, line);
00714 break;
00715
00716 case execute_statement:
00717 if ((*ptr)->data.execute.command)
00718 dfree ((*ptr)->data.execute.command, file, line);
00719 if ((*ptr)->data.execute.arglist)
00720 expression_dereference (&(*ptr) -> data.execute.arglist,
00721 file, line);
00722 break;
00723
00724 case supersede_option_statement:
00725 case send_option_statement:
00726 case default_option_statement:
00727 case append_option_statement:
00728 case prepend_option_statement:
00729 if ((*ptr) -> data.option)
00730 option_cache_dereference (&(*ptr) -> data.option,
00731 file, line);
00732 break;
00733
00734 default:
00735
00736 break;
00737 }
00738
00739 dfree ((*ptr), file, line);
00740 *ptr = (struct executable_statement *)0;
00741 return 1;
00742 }
00743
00744 void write_statements (file, statements, indent)
00745 FILE *file;
00746 struct executable_statement *statements;
00747 int indent;
00748 {
00749 #if defined ENABLE_EXECUTE
00750 struct expression *expr;
00751 #endif
00752 struct executable_statement *r, *x;
00753 const char *s, *t, *dot;
00754 int col;
00755
00756 if (!statements)
00757 return;
00758
00759 for (r = statements; r; r = r -> next) {
00760 switch (r -> op) {
00761 case statements_statement:
00762 write_statements (file, r -> data.statements, indent);
00763 break;
00764
00765 case on_statement:
00766 indent_spaces (file, indent);
00767 fprintf (file, "on ");
00768 s = "";
00769 if (r -> data.on.evtypes & ON_EXPIRY) {
00770 fprintf (file, "%sexpiry", s);
00771 s = " or ";
00772 }
00773 if (r -> data.on.evtypes & ON_COMMIT) {
00774 fprintf (file, "%scommit", s);
00775 s = " or ";
00776 }
00777 if (r -> data.on.evtypes & ON_RELEASE) {
00778 fprintf (file, "%srelease", s);
00779
00780 }
00781 if (r -> data.on.statements) {
00782 fprintf (file, " {");
00783 write_statements (file,
00784 r -> data.on.statements,
00785 indent + 2);
00786 indent_spaces (file, indent);
00787 fprintf (file, "}");
00788 } else {
00789 fprintf (file, ";");
00790 }
00791 break;
00792
00793 case switch_statement:
00794 indent_spaces (file, indent);
00795 fprintf (file, "switch (");
00796 col = write_expression (file,
00797 r -> data.s_switch.expr,
00798 indent + 7, indent + 7, 1);
00799 col = token_print_indent (file, col, indent + 7,
00800 "", "", ")");
00801 token_print_indent (file,
00802 col, indent, " ", "", "{");
00803 write_statements (file, r -> data.s_switch.statements,
00804 indent + 2);
00805 indent_spaces (file, indent);
00806 fprintf (file, "}");
00807 break;
00808
00809 case case_statement:
00810 indent_spaces (file, indent - 1);
00811 fprintf (file, "case ");
00812 col = write_expression (file,
00813 r -> data.s_switch.expr,
00814 indent + 5, indent + 5, 1);
00815 token_print_indent (file, col, indent + 5,
00816 "", "", ":");
00817 break;
00818
00819 case default_statement:
00820 indent_spaces (file, indent - 1);
00821 fprintf (file, "default: ");
00822 break;
00823
00824 case if_statement:
00825 indent_spaces (file, indent);
00826 fprintf (file, "if ");
00827 x = r;
00828 col = write_expression (file,
00829 x -> data.ie.expr,
00830 indent + 3, indent + 3, 1);
00831 else_if:
00832 token_print_indent (file, col, indent, " ", "", "{");
00833 write_statements (file, x -> data.ie.tc, indent + 2);
00834 if (x -> data.ie.fc &&
00835 x -> data.ie.fc -> op == if_statement &&
00836 !x -> data.ie.fc -> next) {
00837 indent_spaces (file, indent);
00838 fprintf (file, "} elsif ");
00839 x = x -> data.ie.fc;
00840 col = write_expression (file,
00841 x -> data.ie.expr,
00842 indent + 6,
00843 indent + 6, 1);
00844 goto else_if;
00845 }
00846 if (x -> data.ie.fc) {
00847 indent_spaces (file, indent);
00848 fprintf (file, "} else {");
00849 write_statements (file, x -> data.ie.fc,
00850 indent + 2);
00851 }
00852 indent_spaces (file, indent);
00853 fprintf (file, "}");
00854 break;
00855
00856 case eval_statement:
00857 indent_spaces (file, indent);
00858 fprintf (file, "eval ");
00859 (void) write_expression (file, r -> data.eval,
00860 indent + 5, indent + 5, 1);
00861 fprintf (file, ";");
00862 break;
00863
00864 case return_statement:
00865 indent_spaces (file, indent);
00866 fprintf (file, "return;");
00867 break;
00868
00869 case add_statement:
00870 indent_spaces (file, indent);
00871 fprintf (file, "add \"%s\"", r -> data.add -> name);
00872 break;
00873
00874 case break_statement:
00875 indent_spaces (file, indent);
00876 fprintf (file, "break;");
00877 break;
00878
00879 case supersede_option_statement:
00880 case send_option_statement:
00881 s = "supersede";
00882 goto option_statement;
00883
00884 case default_option_statement:
00885 s = "default";
00886 goto option_statement;
00887
00888 case append_option_statement:
00889 s = "append";
00890 goto option_statement;
00891
00892 case prepend_option_statement:
00893 s = "prepend";
00894 option_statement:
00895
00896
00897
00898
00899
00900 if (r -> data.option -> option -> universe ==
00901 &dhcp_universe) {
00902 t = "";
00903 dot = "";
00904 } else {
00905 t = (r -> data.option -> option ->
00906 universe -> name);
00907 dot = ".";
00908 }
00909 indent_spaces (file, indent);
00910 fprintf (file, "%s %s%s%s = ", s, t, dot,
00911 r -> data.option -> option -> name);
00912 col = (indent + strlen (s) + strlen (t) +
00913 strlen (dot) + strlen (r -> data.option ->
00914 option -> name) + 4);
00915 if (r -> data.option -> expression)
00916 write_expression
00917 (file,
00918 r -> data.option -> expression,
00919 col, indent + 8, 1);
00920 else
00921 token_indent_data_string
00922 (file, col, indent + 8, "", "",
00923 &r -> data.option -> data);
00924
00925 fprintf (file, ";");
00926 break;
00927
00928 case set_statement:
00929 indent_spaces (file, indent);
00930 fprintf (file, "set ");
00931 col = token_print_indent (file, indent + 4, indent + 4,
00932 "", "", r -> data.set.name);
00933 (void) token_print_indent (file, col, indent + 4,
00934 " ", " ", "=");
00935 col = write_expression (file, r -> data.set.expr,
00936 indent + 3, indent + 3, 0);
00937 (void) token_print_indent (file, col, indent + 4,
00938 " ", "", ";");
00939 break;
00940
00941 case unset_statement:
00942 indent_spaces (file, indent);
00943 fprintf (file, "unset ");
00944 col = token_print_indent (file, indent + 6, indent + 6,
00945 "", "", r -> data.set.name);
00946 (void) token_print_indent (file, col, indent + 6,
00947 " ", "", ";");
00948 break;
00949
00950 case log_statement:
00951 indent_spaces (file, indent);
00952 fprintf (file, "log ");
00953 col = token_print_indent (file, indent + 4, indent + 4,
00954 "", "", "(");
00955 switch (r -> data.log.priority) {
00956 case log_priority_fatal:
00957 (void) token_print_indent
00958 (file, col, indent + 4, "",
00959 " ", "fatal,");
00960 break;
00961 case log_priority_error:
00962 (void) token_print_indent
00963 (file, col, indent + 4, "",
00964 " ", "error,");
00965 break;
00966 case log_priority_debug:
00967 (void) token_print_indent
00968 (file, col, indent + 4, "",
00969 " ", "debug,");
00970 break;
00971 case log_priority_info:
00972 (void) token_print_indent
00973 (file, col, indent + 4, "",
00974 " ", "info,");
00975 break;
00976 }
00977 col = write_expression (file, r -> data.log.expr,
00978 indent + 4, indent + 4, 0);
00979 (void) token_print_indent (file, col, indent + 4,
00980 "", "", ");");
00981
00982 break;
00983
00984 case execute_statement:
00985 #ifdef ENABLE_EXECUTE
00986 indent_spaces (file, indent);
00987 col = token_print_indent(file, indent + 4, indent + 4,
00988 "", "", "execute");
00989 col = token_print_indent(file, col, indent + 4, " ", "",
00990 "(");
00991 col = token_print_indent(file, col, indent + 4, "\"", "\"", r->data.execute.command);
00992 for (expr = r->data.execute.arglist; expr; expr = expr->data.arg.next) {
00993 col = token_print_indent(file, col, indent + 4, "", " ", ",");
00994 col = write_expression (file, expr->data.arg.val, col, indent + 4, 0);
00995 }
00996 (void) token_print_indent(file, col, indent + 4, "", "", ");");
00997 #else
00998 log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
00999 "is not defined).", MDL);
01000 #endif
01001 break;
01002
01003 default:
01004 log_fatal ("bogus statement type %d\n", r -> op);
01005 }
01006 }
01007 }
01008
01009
01010
01011
01012
01013
01014
01015 int find_matching_case (struct executable_statement **ep,
01016 struct packet *packet, struct lease *lease,
01017 struct client_state *client_state,
01018 struct option_state *in_options,
01019 struct option_state *out_options,
01020 struct binding_scope **scope,
01021 struct expression *expr,
01022 struct executable_statement *stmt)
01023 {
01024 int status, sub;
01025 struct executable_statement *s;
01026
01027 if (is_data_expression (expr)) {
01028 struct data_string cd, ds;
01029 memset (&ds, 0, sizeof ds);
01030 memset (&cd, 0, sizeof cd);
01031
01032 status = (evaluate_data_expression (&ds, packet, lease,
01033 client_state, in_options,
01034 out_options, scope, expr,
01035 MDL));
01036 if (status) {
01037 for (s = stmt; s; s = s -> next) {
01038 if (s -> op == case_statement) {
01039 sub = (evaluate_data_expression
01040 (&cd, packet, lease, client_state,
01041 in_options, out_options,
01042 scope, s->data.c_case, MDL));
01043 if (sub && cd.len == ds.len &&
01044 !memcmp (cd.data, ds.data, cd.len))
01045 {
01046 data_string_forget (&cd, MDL);
01047 data_string_forget (&ds, MDL);
01048 executable_statement_reference
01049 (ep, s->next, MDL);
01050 return 1;
01051 }
01052 data_string_forget (&cd, MDL);
01053 }
01054 }
01055 data_string_forget (&ds, MDL);
01056 }
01057 } else {
01058 unsigned long n, c;
01059 status = evaluate_numeric_expression (&n, packet, lease,
01060 client_state,
01061 in_options, out_options,
01062 scope, expr);
01063
01064 if (status) {
01065 for (s = stmt; s; s = s->next) {
01066 if (s -> op == case_statement) {
01067 sub = (evaluate_numeric_expression
01068 (&c, packet, lease, client_state,
01069 in_options, out_options,
01070 scope, s->data.c_case));
01071 if (sub && n == c) {
01072 executable_statement_reference
01073 (ep, s->next, MDL);
01074 return 1;
01075 }
01076 }
01077 }
01078 }
01079 }
01080
01081
01082
01083 for (s = stmt; s; s = s->next)
01084 if (s->op == default_statement)
01085 break;
01086 if (s) {
01087 executable_statement_reference (ep, s->next, MDL);
01088 return 1;
01089 }
01090 return 0;
01091 }
01092
01093 int executable_statement_foreach (struct executable_statement *stmt,
01094 int (*callback) (struct
01095 executable_statement *,
01096 void *, int),
01097 void *vp, int condp)
01098 {
01099 struct executable_statement *foo;
01100 int ok = 0;
01101
01102 for (foo = stmt; foo; foo = foo->next) {
01103 if ((*callback) (foo, vp, condp) != 0)
01104 ok = 1;
01105 switch (foo->op) {
01106 case null_statement:
01107 break;
01108 case if_statement:
01109 if (executable_statement_foreach (foo->data.ie.tc,
01110 callback, vp, 1))
01111 ok = 1;
01112 if (executable_statement_foreach (foo->data.ie.fc,
01113 callback, vp, 1))
01114 ok = 1;
01115 break;
01116 case add_statement:
01117 break;
01118 case eval_statement:
01119 break;
01120 case break_statement:
01121 break;
01122 case default_option_statement:
01123 break;
01124 case supersede_option_statement:
01125 break;
01126 case append_option_statement:
01127 break;
01128 case prepend_option_statement:
01129 break;
01130 case send_option_statement:
01131 break;
01132 case statements_statement:
01133 if ((executable_statement_foreach
01134 (foo->data.statements, callback, vp, condp)))
01135 ok = 1;
01136 break;
01137 case on_statement:
01138 if ((executable_statement_foreach
01139 (foo->data.on.statements, callback, vp, 1)))
01140 ok = 1;
01141 break;
01142 case switch_statement:
01143 if ((executable_statement_foreach
01144 (foo->data.s_switch.statements, callback, vp, 1)))
01145 ok = 1;
01146 break;
01147 case case_statement:
01148 break;
01149 case default_statement:
01150 break;
01151 case set_statement:
01152 break;
01153 case unset_statement:
01154 break;
01155 case let_statement:
01156 if ((executable_statement_foreach
01157 (foo->data.let.statements, callback, vp, 0)))
01158 ok = 1;
01159 break;
01160 case define_statement:
01161 break;
01162 case log_statement:
01163 case return_statement:
01164 case execute_statement:
01165 break;
01166 }
01167 }
01168 return ok;
01169 }