#ifndef lint
static char copyright[] =
-"$Id: tree.c,v 1.75 2000/02/03 04:31:46 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
+"$Id: tree.c,v 1.76 2000/02/05 17:45:20 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
return 1;
}
+int evaluate_expression (result, packet, lease,
+ in_options, cfg_options, scope, expr)
+ struct binding_value **result;
+ struct packet *packet;
+ struct lease *lease;
+ struct option_state *in_options;
+ struct option_state *cfg_options;
+ struct binding_scope *scope;
+ struct expression *expr;
+{
+ struct binding_value *bv;
+ int status;
+ struct binding *binding;
+
+ bv = (struct binding_value *)0;
+
+ if (expr -> op == expr_variable_reference) {
+ binding = find_binding (scope, expr -> data.variable);
+
+ if (binding && binding -> value) {
+ if (result)
+ binding_value_reference (result,
+ binding -> value,
+ MDL);
+ return 1;
+ } else
+ return 0;
+ } else if (expr -> op == expr_funcall) {
+ struct string_list *s;
+ struct expression *arg;
+ struct binding_scope *ns;
+ struct binding *nb;
+ binding = find_binding (scope, expr -> data.funcall.name);
+
+ if (!binding || !binding -> value) {
+ log_error ("%s: no such function.",
+ expr -> data.funcall.name);
+ return 0;
+ }
+ if (binding -> value -> type != binding_function) {
+ log_error ("%s: not a function.",
+ expr -> data.funcall.name);
+ return 0;
+ }
+
+ /* Create a new binding scope in which to define
+ the arguments to the function. */
+ ns = (struct binding_scope *)0;
+ if (!binding_scope_allocate (&ns, MDL)) {
+ log_error ("%s: can't allocate argument scope.",
+ expr -> data.funcall.name);
+ return 0;
+ }
+
+ arg = expr -> data.funcall.arglist;
+ s = binding -> value -> value.fundef.args;
+ while (arg && s) {
+ nb = dmalloc (sizeof *nb, MDL);
+ if (!nb) {
+ blb:
+ binding_scope_dereference (&ns, MDL);
+ return 0;
+ } else {
+ nb -> name = dmalloc (strlen (s -> string) + 1,
+ MDL);
+ if (nb -> name)
+ strcpy (binding -> name, s -> string);
+ else {
+ dfree (nb, MDL);
+ nb = (struct binding *)0;
+ goto blb;
+ }
+ }
+ evaluate_expression (&nb -> value, packet, lease,
+ in_options, cfg_options, scope,
+ arg -> data.arg.val);
+ nb -> next = ns -> bindings;
+ ns -> bindings = nb;
+ arg = arg -> data.arg.next;
+ s = s -> next;
+ }
+ if (arg) {
+ log_error ("%s: too many arguments.",
+ expr -> data.funcall.name);
+ binding_scope_dereference (&ns, MDL);
+ return 0;
+ }
+ if (s) {
+ log_error ("%s: too few arguments.",
+ expr -> data.funcall.name);
+ binding_scope_dereference (&ns, MDL);
+ return 0;
+ }
+
+ ns -> outer = scope;
+ if (execute_statements
+ (packet, lease, in_options, cfg_options, ns,
+ binding -> value -> value.fundef.statements)) {
+ if (ns -> bindings && ns -> bindings -> name) {
+ binding_value_reference (result,
+ ns -> bindings -> value,
+ MDL);
+ status = 1;
+ } else
+ status = 0;
+ } else
+ status = 0;
+ binding_scope_dereference (&ns, MDL);
+ return status;
+ } else if (is_boolean_expression (expr)) {
+ if (!binding_value_allocate (&bv, MDL))
+ return 0;
+ bv -> type = binding_boolean;
+ status = (evaluate_boolean_expression
+ (&bv -> value.boolean, packet, lease, in_options,
+ cfg_options, scope, expr));
+ } else if (is_numeric_expression (expr)) {
+ if (!binding_value_allocate (&bv, MDL))
+ return 0;
+ bv -> type = binding_numeric;
+ status = (evaluate_numeric_expression
+ (&bv -> value.intval, packet, lease, in_options,
+ cfg_options, scope, expr));
+ } else if (is_data_expression (expr)) {
+ if (!binding_value_allocate (&bv, MDL))
+ return 0;
+ bv -> type = binding_data;
+ status = (evaluate_data_expression
+ (&bv -> value.data, packet, lease, in_options,
+ cfg_options, scope, expr));
+ } else if (is_dns_expression (expr)) {
+#if defined (NSUPDATE)
+ if (!binding_value_allocate (&bv, MDL))
+ return 0;
+ bv -> type = binding_dns;
+ status = (evaluate_dns_expression
+ (&bv -> value.dns, packet, lease, in_options,
+ cfg_options, scope, expr));
+#endif
+ } else {
+ log_error ("%s: invalid expression type: %d",
+ "evaluate_expression", expr -> op);
+ }
+ if (result)
+ binding_value_reference (result, bv, MDL);
+ binding_value_dereference (&bv, MDL);
+
+ return status;
+}
+
+int binding_value_dereference (struct binding_value **v,
+ const char *file, int line)
+{
+ struct binding_value *bv = *v;
+
+ *v = (struct binding_value *)0;
+
+ /* Decrement the reference count. If it's nonzero, we're
+ done. */
+ --(bv -> refcnt);
+ rc_register (file, line, v, bv, bv -> refcnt);
+ if (bv -> refcnt > 0)
+ return 1;
+ if (bv -> refcnt < 0) {
+ log_error ("%s(%d): negative refcnt!", file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history ();
+#endif
+#if defined (POINTER_DEBUG)
+ abort ();
+#else
+ return 0;
+#endif
+ }
+
+ switch (bv -> type) {
+ case binding_boolean:
+ case binding_numeric:
+ break;
+ case binding_data:
+ if (bv -> value.data.buffer)
+ data_string_forget (&bv -> value.data, file, line);
+ break;
+ case binding_dns:
+#if defined (NSUPDATE)
+ if (bv -> value.dns) {
+ if (bv -> value.dns -> r_data) {
+ dfree (bv -> value.dns -> r_data, MDL);
+ bv -> value.dns -> r_data = (unsigned char *)0;
+ }
+ minires_freeupdrec (bv -> value.dns);
+ }
+ break;
+#endif
+ default:
+ log_error ("%s(%d): invalid binding type: %d",
+ file, line, bv -> type);
+ return 0;
+ }
+ dfree (bv, file, line);
+ return 1;
+}
+
#if defined (NSUPDATE)
int evaluate_dns_expression (result, packet, lease, in_options,
cfg_options, scope, expr)
case expr_ns_not_exists:
return 0;
#endif
+ case expr_funcall:
+ log_error ("%s: dns values for functions not supported.",
+ expr -> data.funcall.name);
+ break;
+
+ case expr_variable_reference:
+ log_error ("%s: dns values for variables not supported.",
+ expr -> data.variable);
+ break;
+
case expr_check:
case expr_equal:
case expr_not_equal:
case expr_config_option:
case expr_leased_address:
case expr_null:
- case expr_variable_reference:
log_error ("Data opcode in evaluate_dns_expression: %d",
expr -> op);
return 0;
log_error ("Numeric opcode in evaluate_dns_expression: %d",
expr -> op);
return 0;
+
+ case expr_arg:
+ break;
}
log_error ("Bogus opcode in evaluate_dns_expression: %d",
int bleft, bright;
int sleft, sright;
struct binding *binding;
+ struct binding_value *bv;
switch (expr -> op) {
case expr_check:
binding = find_binding (scope, expr -> data.variable);
if (binding) {
- if (binding -> value.data)
+ if (binding -> value)
*result = 1;
else
*result = 0;
*result = 0;
#if defined (DEBUG_EXPRESSIONS)
log_debug ("boolean: %s? = %s", expr -> variable,
- s0 ? "true" : "false");
+ sleft ? "true" : "false");
#endif
return 1;
+ case expr_variable_reference:
+ binding = find_binding (scope, expr -> data.variable);
+
+ if (binding && binding -> value) {
+ if (binding -> value -> type == binding_boolean) {
+ *result = binding -> value -> value.boolean;
+ sleft = 1;
+ } else {
+ log_error ("binding type %d in %s.",
+ binding -> value -> type,
+ "evaluate_boolean_expression");
+ sleft = 0;
+ }
+ } else
+ sleft = 0;
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug ("boolean: %s = %s", expr -> variable,
+ sleft ? (*result ? "true" : "false") : "NULL");
+#endif
+ return sleft;
+
+ case expr_funcall:
+ bv = (struct binding_value *)0;
+ sleft = evaluate_expression (&bv, packet, lease,
+ in_options, cfg_options,
+ scope, expr);
+ if (sleft) {
+ if (bv -> type != binding_boolean)
+ log_error ("%s() returned type %d in %s.",
+ expr -> data.funcall.name,
+ bv -> type,
+ "evaluate_boolean_expression");
+ else
+ *result = bv -> value.boolean;
+ binding_value_dereference (&bv, MDL);
+ }
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug ("boolean: %s() = %s", expr -> data.funcall.name,
+ sleft ? (*result ? "true" : "false") : "NULL");
+#endif
+ break;
+
case expr_none:
case expr_match:
case expr_substring:
case expr_config_option:
case expr_leased_address:
case expr_null:
- case expr_variable_reference:
case expr_filename:
case expr_sname:
log_error ("Data opcode in evaluate_boolean_expression: %d",
log_error ("dns opcode in evaluate_boolean_expression: %d",
expr -> op);
return 0;
+
+ case expr_arg:
+ break;
}
log_error ("Bogus opcode in evaluate_boolean_expression: %d",
int status;
struct binding *binding;
char *s;
+ struct binding_value *bv;
switch (expr -> op) {
/* Extract N bytes starting at byte M of a data string. */
case expr_variable_reference:
binding = find_binding (scope, expr -> data.variable);
- if (binding) {
- if (binding -> value.data) {
- data_string_copy (result,
- &binding -> value, MDL);
- s0 = 1;
- } else
- s0 = 0;
+ if (binding && binding -> value) {
+ if (binding -> value -> type == binding_data) {
+ data_string_copy (result,
+ &binding -> value -> value.data,
+ MDL);
+ s0 = 1;
+ } else if (binding -> value -> type != binding_data) {
+ log_error ("binding type %d in %s.",
+ binding -> value -> type,
+ "evaluate_data_expression");
+ s0 = 0;
+ } else
+ s0 = 0;
} else
s0 = 0;
#if defined (DEBUG_EXPRESSIONS)
log_debug ("data: %s = %s", expr -> variable,
s0 ? print_hex_1 (result -> len,
- result -> data, 50);
+ result -> data, 50) : "NULL");
#endif
return s0;
+ case expr_funcall:
+ bv = (struct binding_value *)0;
+ s0 = evaluate_expression (&bv, packet, lease,
+ in_options, cfg_options,
+ scope, expr);
+ if (s0) {
+ if (bv -> type != binding_data)
+ log_error ("%s() returned type %d in %s.",
+ expr -> data.funcall.name,
+ bv -> type,
+ "evaluate_data_expression");
+ else
+ data_string_copy (result, &bv -> value.data,
+ MDL);
+ binding_value_dereference (&bv, MDL);
+ }
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug ("data: %s = %s", expr -> funcall.name,
+ s0 ? print_hex_1 (result -> len,
+ result -> data, 50) : "NULL");
+#endif
+ break;
+
/* Extract the filename. */
case expr_filename:
if (packet && packet -> raw -> file [0]) {
log_error ("dns update opcode in evaluate_data_expression: %d",
expr -> op);
return 0;
+ case expr_arg:
+ break;
}
log_error ("Bogus opcode in evaluate_data_expression: %d", expr -> op);
static int inited;
#endif
struct expression *cur, *next;
+ struct binding *binding;
+ struct binding_value *bv;
switch (expr -> op) {
case expr_check:
case expr_config_option:
case expr_leased_address:
case expr_null:
- case expr_variable_reference:
log_error ("Data opcode in evaluate_numeric_expression: %d",
expr -> op);
return 0;
return status;
#endif /* NSUPDATE */
+ case expr_variable_reference:
+ binding = find_binding (scope, expr -> data.variable);
+
+ if (binding && binding -> value) {
+ if (binding -> value -> type == binding_numeric) {
+ *result = binding -> value -> value.intval;
+ status = 1;
+ } else {
+ log_error ("binding type %d in %s.",
+ binding -> value -> type,
+ "evaluate_numeric_expression");
+ status = 0;
+ }
+ } else
+ status = 0;
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug ("numeric: %s = %s", expr -> variable,
+ status ? *result : 0);
+#endif
+ return status;
+
+ case expr_funcall:
+ bv = (struct binding_value *)0;
+ status = evaluate_expression (&bv, packet, lease,
+ in_options, cfg_options,
+ scope, expr);
+ if (status) {
+ if (bv -> type != binding_numeric)
+ log_error ("%s() returned type %d in %s.",
+ expr -> data.funcall.name,
+ bv -> type,
+ "evaluate_numeric_expression");
+ else
+ *result = bv -> value.intval;
+ binding_value_dereference (&bv, MDL);
+ }
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug ("data: %s = %d", expr -> funcall.name,
+ status ? *result : 0);
+#endif
+ break;
+
case expr_ns_add:
case expr_ns_delete:
case expr_ns_exists:
log_error ("dns opcode in evaluate_numeric_expression: %d",
expr -> op);
return 0;
+
+ case expr_arg:
+ break;
}
log_error ("evaluate_numeric_expression: bogus opcode %d", expr -> op);
dfree (expr -> data.variable, file, line);
break;
+ case expr_funcall:
+ if (expr -> data.funcall.name)
+ dfree (expr -> data.funcall.name, file, line);
+ if (expr -> data.funcall.arglist)
+ expression_dereference (&expr -> data.funcall.arglist,
+ file, line);
+ break;
+
+ case expr_arg:
+ if (expr -> data.arg.val)
+ expression_dereference (&expr -> data.arg.val,
+ file, line);
+ if (expr -> data.arg.next)
+ expression_dereference (&expr -> data.arg.next,
+ file, line);
+ break;
+
/* No subexpressions. */
case expr_leased_address:
case expr_lease_time:
expr -> op == expr_host_decl_name ||
expr -> op == expr_leased_address ||
expr -> op == expr_config_option ||
- expr -> op == expr_null ||
- expr -> op == expr_variable_reference);
+ expr -> op == expr_null);
}
int is_numeric_expression (expr)
case expr_ns_delete:
case expr_ns_exists:
case expr_ns_not_exists:
+ case expr_arg:
+ case expr_funcall:
return 100;
case expr_equal:
case expr_ns_exists:
case expr_ns_not_exists:
case expr_dns_transaction:
+ case expr_arg:
+ case expr_funcall:
return context_any;
case expr_equal:
next = bp -> next;
if (bp -> name)
dfree (bp -> name, file, line);
- if (bp -> value.data)
- data_string_forget (&bp -> value, file, line);
+ if (bp -> value)
+ binding_value_dereference (&bp -> value, file, line);
dfree (bp, file, line);
}
scope -> bindings = (struct binding *)0;