mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-09-04 00:05:30 +00:00
- Add switch, case, default and set statements.
- Allow more than one type in a single on statement.
This commit is contained in:
308
common/execute.c
308
common/execute.c
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
static char copyright[] =
|
static char copyright[] =
|
||||||
"$Id: execute.c,v 1.21 1999/10/07 06:35:42 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
"$Id: execute.c,v 1.22 2000/01/08 01:30:29 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
||||||
#endif /* not lint */
|
#endif /* not lint */
|
||||||
|
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
@@ -34,9 +34,11 @@ int execute_statements (packet, lease, in_options, out_options, statements)
|
|||||||
struct option_state *out_options;
|
struct option_state *out_options;
|
||||||
struct executable_statement *statements;
|
struct executable_statement *statements;
|
||||||
{
|
{
|
||||||
struct executable_statement *r;
|
struct executable_statement *r, *e;
|
||||||
int result;
|
int result;
|
||||||
int status;
|
int status;
|
||||||
|
struct binding *binding;
|
||||||
|
struct data_string ds;
|
||||||
|
|
||||||
if (!statements)
|
if (!statements)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -59,30 +61,52 @@ int execute_statements (packet, lease, in_options, out_options, statements)
|
|||||||
|
|
||||||
case on_statement:
|
case on_statement:
|
||||||
if (lease) {
|
if (lease) {
|
||||||
struct executable_statement **d;
|
if (r -> data.on.evtypes & ON_EXPIRY) {
|
||||||
switch (r -> data.on.evtype) {
|
if (lease -> on_expiry)
|
||||||
case expiry:
|
|
||||||
d = &lease -> on_expiry;
|
|
||||||
break;
|
|
||||||
case commit:
|
|
||||||
d = &lease -> on_commit;
|
|
||||||
break;
|
|
||||||
case release:
|
|
||||||
d = &lease -> on_release;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log_fatal ("unknown event type %d %s",
|
|
||||||
r -> data.on.evtype,
|
|
||||||
"in on statement.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (*d)
|
|
||||||
executable_statement_dereference
|
executable_statement_dereference
|
||||||
(d, "execute_statements");
|
(&lease -> on_expiry,
|
||||||
|
"execute_statements");
|
||||||
executable_statement_reference
|
executable_statement_reference
|
||||||
(d, r -> data.on.statements,
|
(&lease -> on_expiry,
|
||||||
|
r -> data.on.statements,
|
||||||
"execute_statements");
|
"execute_statements");
|
||||||
}
|
}
|
||||||
|
if (r -> data.on.evtypes & ON_RELEASE) {
|
||||||
|
if (lease -> on_release)
|
||||||
|
executable_statement_dereference
|
||||||
|
(&lease -> on_release,
|
||||||
|
"execute_statements");
|
||||||
|
executable_statement_reference
|
||||||
|
(&lease -> on_release,
|
||||||
|
r -> data.on.statements,
|
||||||
|
"execute_statements");
|
||||||
|
}
|
||||||
|
if (r -> data.on.evtypes & ON_COMMIT) {
|
||||||
|
if (lease -> on_commit)
|
||||||
|
executable_statement_dereference
|
||||||
|
(&lease -> on_commit,
|
||||||
|
"execute_statements");
|
||||||
|
executable_statement_reference
|
||||||
|
(&lease -> on_commit,
|
||||||
|
r -> data.on.statements,
|
||||||
|
"execute_statements");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case switch_statement:
|
||||||
|
e = find_matching_case (packet, lease,
|
||||||
|
in_options, out_options,
|
||||||
|
r -> data.s_switch.expr,
|
||||||
|
r -> data.s_switch.statements);
|
||||||
|
if (e && !execute_statements (packet, lease,
|
||||||
|
in_options, out_options,
|
||||||
|
e))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* These have no effect when executed. */
|
||||||
|
case case_statement:
|
||||||
|
case default_statement:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case if_statement:
|
case if_statement:
|
||||||
@@ -166,6 +190,65 @@ int execute_statements (packet, lease, in_options, out_options, statements)
|
|||||||
r -> data.option, r -> op));
|
r -> data.option, r -> op));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case set_statement:
|
||||||
|
if (!lease) {
|
||||||
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
|
log_debug ("exec: set %s = NULL",
|
||||||
|
r -> data.set.name);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (&ds, 0, sizeof ds);
|
||||||
|
status = (evaluate_data_expression
|
||||||
|
(&ds, packet, lease, in_options, out_options,
|
||||||
|
r -> data.set.expr));
|
||||||
|
|
||||||
|
for (binding = lease -> bindings;
|
||||||
|
binding; binding = binding -> next) {
|
||||||
|
if (!(strcasecmp
|
||||||
|
(lease -> bindings -> name,
|
||||||
|
r -> data.set.name)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!binding && status) {
|
||||||
|
binding = dmalloc (sizeof *binding,
|
||||||
|
"execute_statements");
|
||||||
|
if (binding) {
|
||||||
|
binding -> name =
|
||||||
|
dmalloc (strlen
|
||||||
|
(r -> data.set.name + 1),
|
||||||
|
"execute_statements");
|
||||||
|
if (binding -> name)
|
||||||
|
strcpy (binding -> name,
|
||||||
|
r -> data.set.name);
|
||||||
|
else
|
||||||
|
dfree (binding,
|
||||||
|
"execute_statements");
|
||||||
|
binding -> next = lease -> bindings;
|
||||||
|
lease -> bindings = binding;
|
||||||
|
} else
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
if (binding) {
|
||||||
|
data_string_forget (&binding -> value,
|
||||||
|
"execute_statements");
|
||||||
|
if (status)
|
||||||
|
data_string_copy
|
||||||
|
(&binding -> value, &ds,
|
||||||
|
"execute_statements");
|
||||||
|
}
|
||||||
|
if (status)
|
||||||
|
data_string_forget (&ds, "execute_statements");
|
||||||
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
|
log_debug ("exec: set %s = %s", r -> data.set.name,
|
||||||
|
(status
|
||||||
|
? print_hex_1 (binding -> value.len,
|
||||||
|
binding -> value.data, 50)
|
||||||
|
: "NULL"));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_fatal ("bogus statement type %d\n", r -> op);
|
log_fatal ("bogus statement type %d\n", r -> op);
|
||||||
}
|
}
|
||||||
@@ -274,6 +357,21 @@ int executable_statement_dereference (ptr, name)
|
|||||||
(&(*ptr) -> data.on.statements, name);
|
(&(*ptr) -> data.on.statements, name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case switch_statement:
|
||||||
|
if ((*ptr) -> data.s_switch.statements)
|
||||||
|
executable_statement_dereference
|
||||||
|
(&(*ptr) -> data.on.statements, name);
|
||||||
|
if ((*ptr) -> data.s_switch.expr)
|
||||||
|
expression_dereference (&(*ptr) -> data.s_switch.expr,
|
||||||
|
name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case case_statement:
|
||||||
|
if ((*ptr) -> data.s_switch.expr)
|
||||||
|
expression_dereference (&(*ptr) -> data.c_case,
|
||||||
|
name);
|
||||||
|
break;
|
||||||
|
|
||||||
case if_statement:
|
case if_statement:
|
||||||
if ((*ptr) -> data.ie.expr)
|
if ((*ptr) -> data.ie.expr)
|
||||||
expression_dereference (&(*ptr) -> data.ie.expr, name);
|
expression_dereference (&(*ptr) -> data.ie.expr, name);
|
||||||
@@ -290,6 +388,14 @@ int executable_statement_dereference (ptr, name)
|
|||||||
expression_dereference (&(*ptr) -> data.eval, name);
|
expression_dereference (&(*ptr) -> data.eval, name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case set_statement:
|
||||||
|
if ((*ptr)->data.set.name)
|
||||||
|
dfree ((*ptr)->data.set.name, name);
|
||||||
|
if ((*ptr)->data.set.expr)
|
||||||
|
expression_dereference (&(*ptr) -> data.set.expr,
|
||||||
|
name);
|
||||||
|
break;
|
||||||
|
|
||||||
case supersede_option_statement:
|
case supersede_option_statement:
|
||||||
case default_option_statement:
|
case default_option_statement:
|
||||||
case append_option_statement:
|
case append_option_statement:
|
||||||
@@ -330,36 +436,65 @@ void write_statements (file, statements, indent)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case on_statement:
|
case on_statement:
|
||||||
switch (r -> data.on.evtype) {
|
|
||||||
case expiry:
|
|
||||||
s = "expiry";
|
|
||||||
break;
|
|
||||||
case commit:
|
|
||||||
s = "commit";
|
|
||||||
break;
|
|
||||||
case release:
|
|
||||||
s = "release";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log_fatal ("unknown event type %d %s",
|
|
||||||
r -> data.on.evtype,
|
|
||||||
"in on statement.");
|
|
||||||
}
|
|
||||||
indent_spaces (file, indent);
|
indent_spaces (file, indent);
|
||||||
fprintf (file, "on %s {", s);
|
fprintf (file, "on ");
|
||||||
|
s = "";
|
||||||
|
if (r -> data.on.evtypes & ON_EXPIRY) {
|
||||||
|
fprintf (file, "expiry");
|
||||||
|
s = "or";
|
||||||
|
}
|
||||||
|
if (r -> data.on.evtypes & ON_COMMIT) {
|
||||||
|
fprintf (file, "commit");
|
||||||
|
s = "or";
|
||||||
|
}
|
||||||
|
if (r -> data.on.evtypes & ON_RELEASE) {
|
||||||
|
fprintf (file, "release");
|
||||||
|
s = "or";
|
||||||
|
}
|
||||||
write_statements (file, r -> data.on.statements,
|
write_statements (file, r -> data.on.statements,
|
||||||
indent + 2);
|
indent + 2);
|
||||||
indent_spaces (file, indent);
|
indent_spaces (file, indent);
|
||||||
fprintf (file, "}");
|
fprintf (file, "}");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case switch_statement:
|
||||||
|
indent_spaces (file, indent);
|
||||||
|
fprintf (file, "switch (");
|
||||||
|
col = write_expression (file,
|
||||||
|
r -> data.s_switch.expr,
|
||||||
|
indent + 7, indent + 7, 1);
|
||||||
|
col = token_print_indent (file, col, indent + 7,
|
||||||
|
"", "", ")");
|
||||||
|
token_print_indent (file,
|
||||||
|
col, indent, " ", "", "{");
|
||||||
|
write_statements (file, r -> data.s_switch.statements,
|
||||||
|
indent + 2);
|
||||||
|
indent_spaces (file, indent);
|
||||||
|
fprintf (file, "}");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case case_statement:
|
||||||
|
indent_spaces (file, indent - 1);
|
||||||
|
fprintf (file, "case ");
|
||||||
|
col = write_expression (file,
|
||||||
|
r -> data.s_switch.expr,
|
||||||
|
indent + 5, indent + 5, 1);
|
||||||
|
token_print_indent (file, col, indent + 5,
|
||||||
|
"", "", ":");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case default_statement:
|
||||||
|
indent_spaces (file, indent - 1);
|
||||||
|
fprintf (file, "default: ");
|
||||||
|
break;
|
||||||
|
|
||||||
case if_statement:
|
case if_statement:
|
||||||
indent_spaces (file, indent);
|
indent_spaces (file, indent);
|
||||||
fprintf (file, "if ");
|
fprintf (file, "if ");
|
||||||
x = r;
|
x = r;
|
||||||
col = write_expression (file,
|
col = write_expression (file,
|
||||||
x -> data.ie.expr,
|
x -> data.ie.expr,
|
||||||
indent + 3, indent + 3);
|
indent + 3, indent + 3, 1);
|
||||||
else_if:
|
else_if:
|
||||||
token_print_indent (file, col, indent, " ", "", "{");
|
token_print_indent (file, col, indent, " ", "", "{");
|
||||||
write_statements (file, x -> data.ie.true, indent + 2);
|
write_statements (file, x -> data.ie.true, indent + 2);
|
||||||
@@ -372,7 +507,7 @@ void write_statements (file, statements, indent)
|
|||||||
col = write_expression (file,
|
col = write_expression (file,
|
||||||
x -> data.ie.expr,
|
x -> data.ie.expr,
|
||||||
indent + 6,
|
indent + 6,
|
||||||
indent + 6);
|
indent + 6, 1);
|
||||||
goto else_if;
|
goto else_if;
|
||||||
}
|
}
|
||||||
if (x -> data.ie.false) {
|
if (x -> data.ie.false) {
|
||||||
@@ -389,7 +524,7 @@ void write_statements (file, statements, indent)
|
|||||||
indent_spaces (file, indent);
|
indent_spaces (file, indent);
|
||||||
fprintf (file, "eval ");
|
fprintf (file, "eval ");
|
||||||
col = write_expression (file, r -> data.eval,
|
col = write_expression (file, r -> data.eval,
|
||||||
indent + 5, indent + 5);
|
indent + 5, indent + 5, 1);
|
||||||
fprintf (file, ";");
|
fprintf (file, ";");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -442,7 +577,7 @@ void write_statements (file, statements, indent)
|
|||||||
write_expression
|
write_expression
|
||||||
(file,
|
(file,
|
||||||
r -> data.option -> expression,
|
r -> data.option -> expression,
|
||||||
col, indent + 8);
|
col, indent + 8, 1);
|
||||||
else
|
else
|
||||||
token_indent_data_string
|
token_indent_data_string
|
||||||
(file, col, indent + 8, "", "",
|
(file, col, indent + 8, "", "",
|
||||||
@@ -451,8 +586,97 @@ void write_statements (file, statements, indent)
|
|||||||
fprintf (file, ";"); /* XXX */
|
fprintf (file, ";"); /* XXX */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case set_statement:
|
||||||
|
indent_spaces (file, indent);
|
||||||
|
fprintf (file, "set ");
|
||||||
|
col = token_print_indent (file, indent + 4, indent + 4,
|
||||||
|
"", "", r -> data.set.name);
|
||||||
|
col = token_print_indent (file, col, indent + 4,
|
||||||
|
" ", " ", "=");
|
||||||
|
col = write_expression (file, r -> data.set.expr,
|
||||||
|
indent + 3, indent + 3, 0);
|
||||||
|
col = token_print_indent (file, col, indent + 4,
|
||||||
|
" ", "", ";");
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_fatal ("bogus statement type %d\n", r -> op);
|
log_fatal ("bogus statement type %d\n", r -> op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find a case statement in the sequence of executable statements that
|
||||||
|
matches the expression, and if found, return the following statement.
|
||||||
|
If no case statement matches, try to find a default statement and
|
||||||
|
return that (the default statement can precede all the case statements).
|
||||||
|
Otherwise, return the null statement. */
|
||||||
|
|
||||||
|
struct executable_statement *find_matching_case (packet, lease,
|
||||||
|
in_options, out_options,
|
||||||
|
expr, stmt)
|
||||||
|
struct packet *packet;
|
||||||
|
struct lease *lease;
|
||||||
|
struct option_state *in_options;
|
||||||
|
struct option_state *out_options;
|
||||||
|
struct expression *expr;
|
||||||
|
struct executable_statement *stmt;
|
||||||
|
{
|
||||||
|
int status, sub;
|
||||||
|
struct executable_statement *s;
|
||||||
|
unsigned long foo;
|
||||||
|
|
||||||
|
if (is_data_expression (expr)) {
|
||||||
|
struct executable_statement *e;
|
||||||
|
struct data_string cd, ds;
|
||||||
|
memset (&ds, 0, sizeof ds);
|
||||||
|
memset (&cd, 0, sizeof cd);
|
||||||
|
|
||||||
|
status = (evaluate_data_expression
|
||||||
|
(&ds, packet, lease, in_options, out_options, expr));
|
||||||
|
if (status) {
|
||||||
|
for (s = stmt; s; s = s -> next) {
|
||||||
|
if (s -> op == case_statement) {
|
||||||
|
sub = (evaluate_data_expression
|
||||||
|
(&cd, packet, lease, in_options,
|
||||||
|
out_options, s -> data.c_case));
|
||||||
|
if (sub && cd.len == ds.len &&
|
||||||
|
!memcmp (cd.data, ds.data, cd.len))
|
||||||
|
{
|
||||||
|
data_string_forget
|
||||||
|
(&cd, "execute_statements");
|
||||||
|
data_string_forget
|
||||||
|
(&ds, "execute_statements");
|
||||||
|
return s -> next;
|
||||||
|
}
|
||||||
|
data_string_forget (&cd, "execute_statements");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_string_forget (&ds, "execute_statements");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned long n, c;
|
||||||
|
status = (evaluate_numeric_expression
|
||||||
|
(&n, packet, lease, in_options, out_options, expr));
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
for (s = stmt; s; s = s -> next) {
|
||||||
|
if (s -> op == case_statement) {
|
||||||
|
sub = (evaluate_numeric_expression
|
||||||
|
(&c, packet, lease, in_options,
|
||||||
|
out_options, s -> data.c_case));
|
||||||
|
if (sub && n == c)
|
||||||
|
return s -> next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't find a matching case statement, look for a default
|
||||||
|
statement and return the statement following it. */
|
||||||
|
for (s = stmt; s; s = s -> next)
|
||||||
|
if (s -> op == default_statement)
|
||||||
|
break;
|
||||||
|
if (s)
|
||||||
|
return s -> next;
|
||||||
|
return (struct executable_statement *)0;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user