#ifndef lint
static char ocopyright[] =
-"$Id: dhclient.c,v 1.110 2000/07/27 09:02:23 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 Internet Software Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.111 2000/08/28 19:36:39 neild Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
/* Run statements that need to be run on transmission. */
if (client -> config -> on_transmission)
execute_statements_in_scope
- ((struct packet *)0, (struct lease *)0,
+ ((struct binding_value **)0,
+ (struct packet *)0, (struct lease *)0,
(lease ? lease -> options : (struct option_state *)0),
*op, &global_scope,
client -> config -> on_transmission,
client_envadd (client, prefix, "server_name",
"%s", lease -> server_name);
- execute_statements_in_scope ((struct packet *)0,
+ execute_statements_in_scope ((struct binding_value **)0,
+ (struct packet *)0,
(struct lease *)0, lease -> options,
lease -> options, &global_scope,
client -> config -> on_receipt,
#ifndef lint
static char copyright[] =
-"$Id: conflex.c,v 1.79 2000/08/24 18:20:47 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: conflex.c,v 1.80 2000/08/28 19:36:27 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
return REQUIRE;
if (!strcasecmp (atom + 1, "etry"))
return RETRY;
+ if (!strcasecmp (atom + 1, "eturn"))
+ return RETURN;
if (!strcasecmp (atom + 1, "enew"))
return RENEW;
if (!strcasecmp (atom + 1, "ebind"))
Any number between zero and the maximum representable size may be
specified as a numeric expression.
.RE
+.SH
+FUNCTIONS
+Functions may be defined with the \fBdefine\fR statement. A function
+definition may occur anywhere that regular statement may appear.
+Functions occupy the same namespace as variables, and obey the same
+scoping rules.
+.PP
+.nf
+define set-hostname(prefix) {
+ option host-name
+ concat (prefix, binary-to-ascii (16, 32, "", leased-address));
+}
+.fi
+.PP
+A function may return a value when used in an expression with the
+\fBreturn\fR statement. A function with no return statement has a
+value of null.
+.PP
+.nf
+define make-hostname(prefix) {
+ return concat (prefix, binary-to-ascii (16, 32, "", leased-address));
+}
+
+option host-name make-hostname("dyn-");
+.fi
+.PP
+.RE
.SH REFERENCE: LOGGING
Logging statements may be used to send information to the standard logging
channels. A logging statement includes an optional priority (\fBfatal\fR,
#ifndef lint
static char copyright[] =
-"$Id: execute.c,v 1.38 2000/08/23 00:32:46 neild Exp $ Copyright (c) 1998-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: execute.c,v 1.39 2000/08/28 19:36:30 neild Exp $ Copyright (c) 1998-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
#include <omapip/omapip_p.h>
-int execute_statements (packet, lease, in_options, out_options, scope,
+int execute_statements (result, packet, lease, in_options, out_options, scope,
statements)
+ struct binding_value **result;
struct packet *packet;
struct lease *lease;
struct option_state *in_options;
struct executable_statement *statements;
{
struct executable_statement *r, *e, *next;
- int result;
+ int rc;
int status;
unsigned long num;
struct binding_scope *outer;
next = (struct executable_statement *)0;
e = (struct executable_statement *)0;
executable_statement_reference (&r, statements, MDL);
- while (r) {
+ while (r && !(result && *result)) {
if (r -> next)
executable_statement_reference (&next, r -> next, MDL);
switch (r -> op) {
#if defined (DEBUG_EXPRESSIONS)
log_debug ("exec: statements");
#endif
- status = execute_statements (packet, lease, in_options,
- out_options, scope,
+ status = execute_statements (result, packet, lease,
+ in_options, out_options,
+ scope,
r -> data.statements);
#if defined (DEBUG_EXPRESSIONS)
log_debug ("exec: statements returns %d", status);
#endif
if (status) {
if (!(execute_statements
- (packet, lease,
+ (result, packet, lease,
in_options, out_options, scope, e))) {
executable_statement_dereference
(&e, MDL);
case if_statement:
status = (evaluate_boolean_expression
- (&result, packet, lease, in_options,
+ (&rc, packet, lease, in_options,
out_options, scope, r -> data.ie.expr));
#if defined (DEBUG_EXPRESSIONS)
log_debug ("exec: if %s", (status
- ? (result ? "true" : "false")
+ ? (rc ? "true" : "false")
: "NULL"));
#endif
/* XXX Treat NULL as false */
if (!status)
- result = 0;
+ rc = 0;
if (!execute_statements
- (packet, lease, in_options, out_options, scope,
- result ? r -> data.ie.true : r -> data.ie.false))
+ (result, packet, lease,
+ in_options, out_options, scope,
+ rc ? r -> data.ie.true : r -> data.ie.false))
return 0;
break;
#endif
break;
+ case return_statement:
+ status = evaluate_expression
+ (result, packet, lease, in_options,
+ out_options, scope, r -> data.retval);
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug ("exec: return: %s",
+ (status ? "succeeded" : "failed"));
+#endif
+ break;
+
case add_statement:
#if defined (DEBUG_EXPRESSIONS)
log_debug ("exec: add %s", (r -> data.add -> name
break;
case set_statement:
+ case define_statement:
if (!scope) {
log_error ("set %s: no scope",
r -> data.set.name);
if (binding -> value)
binding_value_dereference
(&binding -> value, MDL);
- status = (evaluate_expression
- (&binding -> value, packet, lease,
- in_options, out_options,
- scope, r -> data.set.expr));
+ if (r -> op == set_statement) {
+ status = (evaluate_expression
+ (&binding -> value, packet,
+ lease, in_options,
+ out_options, scope,
+ r -> data.set.expr));
+ } else {
+ if (!(binding_value_allocate
+ (&binding -> value, MDL))) {
+ dfree (binding, MDL);
+ binding = (struct binding *)0;
+ }
+ if (binding -> value) {
+ binding -> value -> type =
+ binding_function;
+ (fundef_reference
+ (&binding -> value -> value.fundef,
+ r -> data.set.expr -> data.func,
+ MDL));
+ }
+ }
}
#if defined (DEBUG_EXPRESSIONS)
log_debug ("exec: set %s%s", r -> data.set.name,
binding_scope_reference (&ns -> outer,
*scope, MDL);
execute_statements
- (packet, lease, in_options, out_options,
+ (result, packet, lease,
+ in_options, out_options,
&ns, e -> data.let.statements);
}
if (ns)
specific scopes, so we recursively traverse the scope list, executing
the most outer scope first. */
-void execute_statements_in_scope (packet, lease, in_options, out_options,
- scope, group, limiting_group)
+void execute_statements_in_scope (result, packet, lease, in_options,
+ out_options, scope, group, limiting_group)
+ struct binding_value **result;
struct packet *packet;
struct lease *lease;
struct option_state *in_options;
}
if (group -> next)
- execute_statements_in_scope (packet, lease,
+ execute_statements_in_scope (result, packet, lease,
in_options, out_options, scope,
group -> next, limiting_group);
- execute_statements (packet, lease, in_options, out_options, scope,
- group -> statements);
+ execute_statements (result, packet, lease, in_options, out_options,
+ scope, group -> statements);
}
/* Dereference or free any subexpressions of a statement being freed. */
file, line);
break;
+ case return_statement:
+ if ((*ptr) -> data.eval)
+ expression_dereference (&(*ptr) -> data.eval,
+ file, line);
+ break;
+
case set_statement:
if ((*ptr)->data.set.name)
dfree ((*ptr)->data.set.name, file, line);
fprintf (file, ";");
break;
+ case return_statement:
+ indent_spaces (file, indent);
+ fprintf (file, "return;");
+ break;
+
case add_statement:
indent_spaces (file, indent);
fprintf (file, "add \"%s\"", r -> data.add -> name);
#ifndef lint
static char copyright[] =
-"$Id: parse.c,v 1.79 2000/08/22 21:51:30 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: parse.c,v 1.80 2000/08/28 19:36:31 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
parse_semi (cfile);
break;
+ case RETURN:
+ token = next_token (&val, cfile);
+
+ if (!executable_statement_allocate (result, MDL))
+ log_fatal ("no memory for return statement.");
+ (*result) -> op = return_statement;
+
+ if (!parse_expression (&(*result) -> data.retval,
+ cfile, lose, context_data,
+ (struct expression **)0, expr_none)) {
+ if (!*lose)
+ parse_warn (cfile,
+ "expecting data expression.");
+ else
+ *lose = 1;
+ skip_to_semi (cfile);
+ executable_statement_dereference (result, MDL);
+ return 0;
+ }
+ parse_semi (cfile);
+ break;
+
case LOG:
- /** XXXDPN: At work. **/
token = next_token (&val, cfile);
if (!executable_statement_allocate (result, MDL))
supersede_option_statement);
}
}
+
+ if (token == NUMBER_OR_NAME || token == NAME) {
+ /* This is rather ugly. Since function calls are
+ data expressions, fake up an eval statement. */
+ if (!executable_statement_allocate (result, MDL))
+ log_fatal ("no memory for eval statement.");
+ (*result) -> op = eval_statement;
+
+ if (!parse_expression (&(*result) -> data.eval,
+ cfile, lose, context_data,
+ (struct expression **)0,
+ expr_none)) {
+ if (!*lose)
+ parse_warn (cfile, "expecting "
+ "function call.");
+ else
+ *lose = 1;
+ skip_to_semi (cfile);
+ executable_statement_dereference (result, MDL);
+ return 0;
+ }
+ parse_semi (cfile);
+ break;
+ }
+
*lose = 0;
return 0;
}
#ifndef lint
static char copyright[] =
-"$Id: tree.c,v 1.86 2000/08/22 21:21:54 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: tree.c,v 1.87 2000/08/28 19:36:32 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
if (scope && *scope)
binding_scope_reference (&ns -> outer, *scope, MDL);
- 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;
+ status = (execute_statements
+ (&bv, packet, lease, in_options, cfg_options, &ns,
+ binding -> value -> value.fundef -> statements));
binding_scope_dereference (&ns, MDL);
- return status;
- } else if (expr -> op == expr_funcall) {
- /* XXXDPN: This can never happen. Huh? */
- if (!binding_value_allocate (&bv, MDL))
- return 0;
- bv -> type = binding_function;
- fundef_reference (&bv -> value.fundef, expr -> data.func, MDL);
- return 1;
+
+ if (!bv)
+ return 1;
} else if (is_boolean_expression (expr)) {
if (!binding_value_allocate (&bv, MDL))
return 0;
} else {
log_error ("%s: invalid expression type: %d",
"evaluate_expression", expr -> op);
+ return 0;
}
if (result)
binding_value_reference (result, bv, MDL);
int bill_class PROTO ((struct lease *, struct class *));
/* execute.c */
-int execute_statements PROTO ((struct packet *,
+int execute_statements PROTO ((struct binding_value **result,
+ struct packet *,
struct lease *,
struct option_state *, struct option_state *,
struct binding_scope **,
struct executable_statement *));
-void execute_statements_in_scope PROTO ((struct packet *,
+void execute_statements_in_scope PROTO ((struct binding_value **result,
+ struct packet *,
struct lease *,
struct option_state *,
struct option_state *,
FATAL = 582,
ERROR = 583,
TOKEN_DEBUG = 584,
- INFO = 585
+ INFO = 585,
+ RETURN = 586
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
unset_statement,
let_statement,
define_statement,
- log_statement
+ log_statement,
+ return_statement
} op;
union {
struct {
struct expression *expr;
} ie;
struct expression *eval;
+ struct expression *retval;
struct class *add;
struct option_cache *option;
struct option_cache *supersede;
#ifndef lint
static char copyright[] =
-"$Id: bootp.c,v 1.64 2000/08/24 18:43:11 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: bootp.c,v 1.65 2000/08/28 19:36:08 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
option_state_allocate (&options, MDL);
/* Execute the subnet statements. */
- execute_statements_in_scope (packet, lease, packet -> options, options,
+ execute_statements_in_scope ((struct binding_value **)0,
+ packet, lease, packet -> options, options,
&lease -> scope, lease -> subnet -> group,
(struct group *)0);
/* Execute statements from class scopes. */
for (i = packet -> class_count; i > 0; i--) {
execute_statements_in_scope
- (packet, lease, packet -> options, options,
+ ((struct binding_value **)0,
+ packet, lease, packet -> options, options,
&lease -> scope, packet -> classes [i - 1] -> group,
lease -> subnet -> group);
}
/* Execute the host statements. */
- execute_statements_in_scope (packet, lease, packet -> options, options,
+ execute_statements_in_scope ((struct binding_value **)0,
+ packet, lease, packet -> options, options,
&lease -> scope,
hp -> group, subnet -> group);
}
/* Execute the commit statements, if there are any. */
- execute_statements (packet, lease, packet -> options,
+ execute_statements ((struct binding_value **)0,
+ packet, lease, packet -> options,
options, &lease -> scope, lease -> on_commit);
/* We're done with the option state. */
#ifndef lint
static char copyright[] =
-"$Id: class.c,v 1.20 2000/05/16 23:03:36 mellon Exp $ Copyright (c) 1998-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: class.c,v 1.21 2000/08/28 19:36:09 neild Exp $ Copyright (c) 1998-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
void classify_client (packet)
struct packet *packet;
{
- execute_statements (packet, (struct lease *)0, packet -> options,
+ execute_statements ((struct binding_value **)0,
+ packet, (struct lease *)0, packet -> options,
(struct option_state *)0, &global_scope,
default_classification_rules);
}
#ifndef lint
static char copyright[] =
-"$Id: dhcp.c,v 1.160 2000/08/24 18:49:34 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dhcp.c,v 1.161 2000/08/28 19:36:10 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
/* Execute statements in scope starting with the subnet scope. */
if (lease)
- execute_statements_in_scope (packet, (struct lease *)0,
+ execute_statements_in_scope ((struct binding_value **)0,
+ packet, (struct lease *)0,
packet -> options, options,
&global_scope,
lease -> subnet -> group,
/* Execute statements in the class scopes. */
for (i = packet -> class_count; i > 0; i--) {
execute_statements_in_scope
- (packet, (struct lease *)0, packet -> options, options,
+ ((struct binding_value **)0,
+ packet, (struct lease *)0, packet -> options, options,
&global_scope, packet -> classes [i - 1] -> group,
lease ? lease -> subnet -> group : (struct group *)0);
}
/* Execute statements in scope starting with the subnet scope. */
if (subnet)
- execute_statements_in_scope (packet, (struct lease *)0,
+ execute_statements_in_scope ((struct binding_value **)0,
+ packet, (struct lease *)0,
packet -> options, options,
&global_scope, subnet -> group,
(struct group *)0);
/* Execute statements in the class scopes. */
for (i = packet -> class_count; i > 0; i--) {
execute_statements_in_scope
- (packet, (struct lease *)0, packet -> options, options,
+ ((struct binding_value **)0,
+ packet, (struct lease *)0, packet -> options, options,
&global_scope, packet -> classes [i - 1] -> group,
subnet ? subnet -> group : (struct group *)0);
}
}
/* Execute statements in scope starting with the subnet scope. */
- execute_statements_in_scope (packet, lease,
+ execute_statements_in_scope ((struct binding_value **)0,
+ packet, lease,
packet -> options,
state -> options, &lease -> scope,
lease -> subnet -> group,
/* If the lease is from a pool, run the pool scope. */
if (lease -> pool)
- execute_statements_in_scope (packet, lease,
+ execute_statements_in_scope ((struct binding_value **)0,
+ packet, lease,
packet -> options,
state -> options, &lease -> scope,
lease -> pool -> group,
/* Execute statements from class scopes. */
for (i = packet -> class_count; i > 0; i--) {
execute_statements_in_scope
- (packet, lease, packet -> options, state -> options,
+ ((struct binding_value **)0,
+ packet, lease, packet -> options, state -> options,
&lease -> scope, packet -> classes [i - 1] -> group,
(lease -> pool
? lease -> pool -> group
/* If we have a host_decl structure, run the options associated
with its group. */
if (lease -> host)
- execute_statements_in_scope (packet, lease, packet -> options,
+ execute_statements_in_scope ((struct binding_value **)0,
+ packet, lease, packet -> options,
state -> options, &lease -> scope,
lease -> host -> group,
(lease -> pool
/* If there are statements to execute when the lease is
committed, execute them. */
if (lease -> on_commit && (!offer || offer == DHCPACK)) {
- execute_statements (packet, lt, packet -> options,
+ execute_statements ((struct binding_value **)0,
+ packet, lt, packet -> options,
state -> options, &lease -> scope,
lease -> on_commit);
if (lease -> on_commit)
#ifndef lint
static char ocopyright[] =
-"$Id: dhcpd.c,v 1.99 2000/08/07 20:28:13 neild Exp $ Copyright 1995-2000 Internet Software Consortium.";
+"$Id: dhcpd.c,v 1.100 2000/08/28 19:36:12 neild Exp $ Copyright 1995-2000 Internet Software Consortium.";
#endif
static char copyright[] =
/* Now try to get the lease file name. */
option_state_allocate (&options, MDL);
- execute_statements_in_scope ((struct packet *)0,
+ execute_statements_in_scope ((struct binding_value **)0,
+ (struct packet *)0,
(struct lease *)0,
(struct option_state *)0,
options, &global_scope,
#ifndef lint
static char copyright[] =
-"$Id: mdb.c,v 1.41 2000/07/27 09:03:08 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
+"$Id: mdb.c,v 1.42 2000/08/28 19:36:13 neild Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
lease -> binding_state == FTS_RESERVED) &&
lease -> next_binding_state != FTS_RELEASED) {
if (lease -> on_expiry) {
- execute_statements ((struct packet *)0, lease,
+ execute_statements ((struct binding_value **)0,
+ (struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
lease -> binding_state == FTS_RESERVED) &&
lease -> next_binding_state == FTS_RELEASED) {
if (lease -> on_release) {
- execute_statements ((struct packet *)0, lease,
+ execute_statements ((struct binding_value **)0,
+ (struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
/* If there are statements to execute when the lease is
released, execute them. */
if (lease -> on_release) {
- execute_statements (packet, lease, packet -> options,
+ execute_statements ((struct binding_value **)0,
+ packet, lease, packet -> options,
(struct option_state *)0, /* XXX */
&lease -> scope, lease -> on_release);
if (lease -> on_release)