From: Ted Lemon Date: Fri, 16 Jul 1999 21:34:14 +0000 (+0000) Subject: Massive rototill to support some new DDNS features. X-Git-Tag: V3-BETA-1-PATCH-2~5^2~196 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=79a65726f0c4e83eea3f65e8c1fc88f882b06c12;p=thirdparty%2Fdhcp.git Massive rototill to support some new DDNS features. --- diff --git a/common/alloc.c b/common/alloc.c index 84aabc2db..3eb73cbb9 100644 --- a/common/alloc.c +++ b/common/alloc.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: alloc.c,v 1.30 1999/05/27 12:38:05 mellon Exp $ Copyright (c) 1995, 1996, 1998 The Internet Software Consortium. All rights reserved.\n"; +"$Id: alloc.c,v 1.31 1999/07/16 21:33:57 mellon Exp $ Copyright (c) 1995, 1996, 1998 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -777,3 +777,69 @@ int option_state_dereference (ptr, name) dfree (options, name); return 1; } + +int executable_statement_allocate (ptr, name) + struct executable_statement **ptr; + char *name; +{ + struct executable_statement *bp; + + bp = dmalloc (sizeof *bp, name); + if (!bp) + return 0; + memset (bp, 0, sizeof *bp); + bp -> refcnt = 0; + return executable_statement_reference (ptr, bp, name); +} + +int executable_statement_reference (ptr, bp, name) + struct executable_statement **ptr; + struct executable_statement *bp; + char *name; +{ + if (!ptr) { + log_error ("Null ptr in executable_statement_reference: %s", + name); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("Nonnull ptr in executable_statement_reference: %s", + name); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct executable_statement *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + return 1; +} + +int executable_statement_dereference (ptr, name) + struct executable_statement **ptr; + char *name; +{ + struct executable_statement *bp; + + if (!ptr || !*ptr) { + log_error ("Null ptr in executable_statement_dereference: %s", + name); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + (*ptr) -> refcnt--; + if (!(*ptr) -> refcnt) + dfree ((*ptr), name); + *ptr = (struct executable_statement *)0; + return 1; +} + diff --git a/common/conflex.c b/common/conflex.c index deb099b8c..1d88882a7 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: conflex.c,v 1.48 1999/07/06 20:41:22 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: conflex.c,v 1.49 1999/07/16 21:33:58 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -384,8 +384,12 @@ static enum dhcp_token intern (atom, dfv) return BOOLEAN; break; case 'c': + if (!strcasecmp (atom + 1, "ommit")) + return COMMIT; if (!strcasecmp (atom + 1, "ode")) return CODE; + if (!strcasecmp (atom + 1, "onfig-option")) + return CONFIG_OPTION; if (!strcasecmp (atom + 1, "heck")) return CHECK; if (!strcasecmp (atom + 1, "lass")) @@ -436,6 +440,8 @@ static enum dhcp_token intern (atom, dfv) } break; case 'e': + if (!strcasecmp (atom + 1, "xpiry")) + return EXPIRY; if (isascii (atom [1]) && tolower (atom [1]) == 'x') { if (!strcasecmp (atom + 2, "tract-int")) return EXTRACT_INT; @@ -477,6 +483,8 @@ static enum dhcp_token intern (atom, dfv) case 'h': if (!strcasecmp (atom + 1, "ost")) return HOST; + if (!strcasecmp (atom + 1, "ost-decl-name")) + return HOST_DECL_NAME; if (!strcasecmp (atom + 1, "ardware")) return HARDWARE; if (!strcasecmp (atom + 1, "ostname")) @@ -553,6 +561,8 @@ static enum dhcp_token intern (atom, dfv) case 'o': if (!strcasecmp (atom + 1, "r")) return OR; + if (!strcasecmp (atom + 1, "n")) + return ON; if (!strcasecmp (atom + 1, "ption")) return OPTION; if (!strcasecmp (atom + 1, "ne-lease-per-client")) @@ -583,6 +593,8 @@ static enum dhcp_token intern (atom, dfv) return PORT; if (!strcasecmp (atom + 1, "otential-conflict")) return POTENTIAL_CONFLICT; + if (!strcasecmp (atom + 1, "ick-first-value")) + return PICK_FIRST_VALUE; break; case 'r': if (!strcasecmp (atom + 1, "ange")) @@ -607,6 +619,8 @@ static enum dhcp_token intern (atom, dfv) return REJECT; if (!strcasecmp (atom + 1, "everse")) return REVERSE; + if (!strcasecmp (atom + 1, "elease")) + return RELEASE; break; case 's': if (!strcasecmp (atom + 1, "igned")) diff --git a/common/execute.c b/common/execute.c index 2c4eb8c4b..72e5245df 100644 --- a/common/execute.c +++ b/common/execute.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: execute.c,v 1.10 1999/07/02 20:57:24 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: execute.c,v 1.11 1999/07/16 21:33:58 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -43,6 +43,46 @@ int execute_statements (packet, lease, in_options, out_options, statements) for (r = statements; r; r = r -> next) { switch (r -> op) { + case statements_statement: + log_info ("exec: statements"); + if (!execute_statements (packet, lease, + in_options, out_options, + r -> data.statements.car)) + return 0; + if (!execute_statements (packet, lease, + in_options, out_options, + r -> data.statements.cdr)) + return 0; + break; + + case on_statement: + if (lease) { + struct executable_statement **d; + switch (r -> data.on.evtype) { + 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 + (d, "execute_statements"); + executable_statement_reference + (d, r -> data.on.statements, + "execute_statements"); + } + break; + case if_statement: status = evaluate_boolean_expression (&result, packet, diff --git a/common/parse.c b/common/parse.c index fe74b9ec6..fed33e134 100644 --- a/common/parse.c +++ b/common/parse.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: parse.c,v 1.28 1999/07/06 20:41:22 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: parse.c,v 1.29 1999/07/16 21:33:59 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -1151,27 +1151,29 @@ int parse_cshl (data, cfile) * APPEND option-parameter SEMI */ -struct executable_statement *parse_executable_statements (cfile, lose) +int parse_executable_statements (statements, cfile, lose) + struct executable_statement **statements; FILE *cfile; int *lose; { - struct executable_statement *head, **next; + struct executable_statement **next; - next = &head; - while ((*next = parse_executable_statement (cfile, lose))) + next = statements; + while (parse_executable_statement (next, cfile, lose)) next = &((*next) -> next); if (!*lose) - return head; - return (struct executable_statement *)0; + return 1; + return 0; } -struct executable_statement *parse_executable_statement (cfile, lose) +int parse_executable_statement (result, cfile, lose) + struct executable_statement **result; FILE *cfile; int *lose; { enum dhcp_token token; char *val; - struct executable_statement *stmt, base; + struct executable_statement base; struct class *cta; struct option *option; struct option_cache *cache; @@ -1180,8 +1182,8 @@ struct executable_statement *parse_executable_statement (cfile, lose) switch (token) { case IF: next_token (&val, cfile); - stmt = parse_if_statement (cfile, lose); - return stmt; + return parse_if_statement (result, cfile, lose); + case TOKEN_ADD: token = next_token (&val, cfile); token = next_token (&val, cfile); @@ -1189,39 +1191,43 @@ struct executable_statement *parse_executable_statement (cfile, lose) parse_warn ("expecting class name."); skip_to_semi (cfile); *lose = 1; - return (struct executable_statement *)0; + return 0; } cta = find_class (val); if (!cta) { parse_warn ("unknown class %s.", val); skip_to_semi (cfile); *lose = 1; - return (struct executable_statement *)0; + return 0; } if (!parse_semi (cfile)) { *lose = 1; - return (struct executable_statement *)0; + return 0; } - memset (&base, 0, sizeof base); - base.op = add_statement; - base.data.add = cta; + if (!executable_statement_allocate + (result, "parse_executable_statement")) + log_fatal ("no memory for new statement."); + (*result) -> op = add_statement; + (*result) -> data.add = cta; break; case BREAK: token = next_token (&val, cfile); if (!parse_semi (cfile)) { *lose = 1; - return (struct executable_statement *)0; + return 0; } - memset (&base, 0, sizeof base); - base.op = break_statement; + if (!executable_statement_allocate + (result, "parse_executable_statement")) + log_fatal ("no memory for new statement."); + (*result) -> op = break_statement; break; case SEND: *lose = 1; parse_warn ("send not appropriate here."); skip_to_semi (cfile); - return (struct executable_statement *)0; + return 0; case SUPERSEDE: case OPTION: @@ -1229,9 +1235,9 @@ struct executable_statement *parse_executable_statement (cfile, lose) option = parse_option_name (cfile, 0); if (!option) { *lose = 1; - return (struct executable_statement *)0; + return 0; } - return parse_option_statement (cfile, 1, option, + return parse_option_statement (result, cfile, 1, option, supersede_option_statement); case ALLOW: @@ -1240,10 +1246,12 @@ struct executable_statement *parse_executable_statement (cfile, lose) cache = (struct option_cache *)0; if (!parse_allow_deny (&cache, cfile, token == ALLOW ? 1 : 0)) - return (struct executable_statement *)0; - memset (&base, 0, sizeof base); - base.op = supersede_option_statement; - base.data.option = cache; + return 0; + if (!executable_statement_allocate + (result, "parse_executable_statement")) + log_fatal ("no memory for new statement."); + (*result) -> op = supersede_option_statement; + (*result) -> data.option = cache; break; case DEFAULT: @@ -1251,9 +1259,9 @@ struct executable_statement *parse_executable_statement (cfile, lose) option = parse_option_name (cfile, 0); if (!option) { *lose = 1; - return (struct executable_statement *)0; + return 0; } - return parse_option_statement (cfile, 1, option, + return parse_option_statement (result, cfile, 1, option, default_option_statement); case PREPEND: @@ -1261,9 +1269,9 @@ struct executable_statement *parse_executable_statement (cfile, lose) option = parse_option_name (cfile, 0); if (!option) { *lose = 1; - return (struct executable_statement *)0; + return 0; } - return parse_option_statement (cfile, 1, option, + return parse_option_statement (result, cfile, 1, option, prepend_option_statement); case APPEND: @@ -1271,23 +1279,96 @@ struct executable_statement *parse_executable_statement (cfile, lose) option = parse_option_name (cfile, 0); if (!option) { *lose = 1; - return (struct executable_statement *)0; + return 0; } - return parse_option_statement (cfile, 1, option, + return parse_option_statement (result, cfile, 1, option, append_option_statement); + case ON: + token = next_token (&val, cfile); + + return parse_on_statement (result, cfile, lose); + default: *lose = 0; - return (struct executable_statement *)0; + return 0; } - stmt = ((struct executable_statement *) - dmalloc (sizeof (struct executable_statement), - "parse_executable_statement")); - if (!stmt) + return 1; +} + +/* + * on-statement :== event-type LBRACE executable-statements RBRACE + * + * event-type :== EXPIRY | COMMIT | RELEASE + */ + +int parse_on_statement (result, cfile, lose) + struct executable_statement **result; + FILE *cfile; + int *lose; +{ + enum dhcp_token token; + char *val; + + if (!executable_statement_allocate (result, + "parse_executable_statement")) log_fatal ("no memory for new statement."); - *stmt = base; - return stmt; + + token = next_token (&val, cfile); + switch (token) { + case EXPIRY: + (*result) -> data.on.evtype = expiry; + break; + + case COMMIT: + (*result) -> data.on.evtype = expiry; + break; + + case RELEASE: + (*result) -> data.on.evtype = expiry; + break; + + default: + parse_warn ("expecting a lease event type"); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference + (result, "parse_on_statement"); + break; + } + + token = next_token (&val, cfile); + if (token != LBRACE) { + parse_warn ("left brace expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, + "parse_on_statement"); + return 0; + } + if (!parse_executable_statements (&(*result) -> data.on.statements, + cfile, lose)) { + if (*lose) { + /* Try to even things up. */ + do { + token = next_token (&val, cfile); + } while (token != EOF && token != RBRACE); + executable_statement_dereference + (result, "parse_on_statement"); + return 0; + } + } + token = next_token (&val, cfile); + if (token != RBRACE) { + parse_warn ("right brace expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference + (result, "parse_on_statement"); + return 0; + } + return 1; } /* @@ -1300,21 +1381,26 @@ struct executable_statement *parse_executable_statement (cfile, lose) * ELSIF if-statement */ -struct executable_statement *parse_if_statement (cfile, lose) +int parse_if_statement (result, cfile, lose) + struct executable_statement **result; FILE *cfile; int *lose; { enum dhcp_token token; char *val; - struct executable_statement *stmt; - struct expression *if_condition; - struct executable_statement *true, *false; - if_condition = (struct expression *)0; - if (!parse_boolean_expression (&if_condition, cfile, lose)) { + if (!executable_statement_allocate (result, "parse_if_statement")) + log_fatal ("no memory for if statement."); + + (*result) -> op = if_statement; + + if (!parse_boolean_expression (&(*result) -> data.ie.expr, + cfile, lose)) { if (!*lose) parse_warn ("boolean expression expected."); - return (struct executable_statement *)0; + executable_statement_dereference (result, + "parse_if_statement"); + return 0; } #if defined (DEBUG_EXPRESSION_PARSE) print_expression ("if condition", if_condition); @@ -1324,22 +1410,30 @@ struct executable_statement *parse_if_statement (cfile, lose) parse_warn ("left brace expected."); skip_to_semi (cfile); *lose = 1; - return (struct executable_statement *)0; + executable_statement_dereference (result, + "parse_if_statement"); + return 0; } - true = parse_executable_statements (cfile, lose); - token = next_token (&val, cfile); - if (*lose) { - /* Try to even things up. */ - do { - token = next_token (&val, cfile); - } while (token != EOF && token != RBRACE); - return (struct executable_statement *)0; + if (!parse_executable_statements (&(*result) -> data.ie.true, + cfile, lose)) { + if (*lose) { + /* Try to even things up. */ + do { + token = next_token (&val, cfile); + } while (token != EOF && token != RBRACE); + executable_statement_dereference + (result, "parse_if_statement"); + return 0; + } } + token = next_token (&val, cfile); if (token != RBRACE) { parse_warn ("right brace expected."); skip_to_semi (cfile); *lose = 1; - return (struct executable_statement *)0; + executable_statement_dereference + (result, "parse_if_statement"); + return 0; } token = peek_token (&val, cfile); if (token == ELSE) { @@ -1347,46 +1441,53 @@ struct executable_statement *parse_if_statement (cfile, lose) token = peek_token (&val, cfile); if (token == IF) { token = next_token (&val, cfile); - false = parse_if_statement (cfile, lose); - if (*lose) - return (struct executable_statement *)0; + if (!parse_if_statement (&(*result) -> data.ie.false, + cfile, lose)) { + if (*lose) { + return 0; + executable_statement_dereference + (result, "parse_if_statement"); + } + } } else if (token != LBRACE) { parse_warn ("left brace or if expected."); skip_to_semi (cfile); *lose = 1; - return (struct executable_statement *)0; + executable_statement_dereference + (result, "parse_if_statement"); + return 0; } else { token = next_token (&val, cfile); - false = parse_executable_statements (cfile, lose); - if (*lose) - return (struct executable_statement *)0; + if (!parse_if_statement (&(*result) -> data.ie.false, + cfile, lose)) { + executable_statement_dereference + (result, "parse_if_statement"); + return 0; + } token = next_token (&val, cfile); if (token != RBRACE) { parse_warn ("right brace expected."); skip_to_semi (cfile); *lose = 1; - return (struct executable_statement *)0; + executable_statement_dereference + (result, "parse_if_statement"); + return 0; } } } else if (token == ELSIF) { token = next_token (&val, cfile); - false = parse_if_statement (cfile, lose); - if (*lose) - return (struct executable_statement *)0; + if (!parse_if_statement (&(*result) -> data.ie.false, + cfile, lose)) { + if (*lose) { + return 0; + executable_statement_dereference + (result, "parse_if_statement"); + } + } } else - false = (struct executable_statement *)0; + (*result) -> data.ie.false = (struct executable_statement *)0; - stmt = ((struct executable_statement *) - dmalloc (sizeof (struct executable_statement), - "parse_if_statement")); - if (!stmt) - log_fatal ("no memory for if statement."); - memset (stmt, 0, sizeof *stmt); - stmt -> op = if_statement; - stmt -> data.ie.expr = if_condition; - stmt -> data.ie.true = true; - stmt -> data.ie.false = false; - return stmt; + return 1; } /* @@ -1486,6 +1587,7 @@ int parse_non_binary (expr, cfile, lose, context) char *val; struct collection *col; struct option *option; + struct expression *nexp; token = peek_token (&val, cfile); @@ -1746,11 +1848,49 @@ int parse_non_binary (expr, cfile, lose, context) goto norparen; break; - case OPTION: + case PICK_FIRST_VALUE: + /* pick (a, b, c) actually produces an internal representation + that looks like pick (a, pick (b, pick (c, nil))). */ + token = next_token (&val, cfile); + if (!(expression_allocate + (expr, "parse_expression: PICK_FIRST_VALUE"))) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_reverse; + token = next_token (&val, cfile); + if (token != LPAREN) + goto nolparen; + + nexp = *expr; + do { + struct expression *tmp = (struct expression *)0; + if (!(parse_data_expression + (&nexp -> data.pick_first_value.car, + cfile, lose))) + goto nodata; + + token = next_token (&val, cfile); + if (token == COMMA) { + if (!(expression_allocate + (&nexp -> data.pick_first_value.cdr, + "parse_expression: PICK_FIRST_VALUE"))) + log_fatal ("can't allocate expr"); + nexp = nexp -> data.pick_first_value.cdr; + } + } while (token == COMMA); + + if (token != RPAREN) + goto norparen; + break; + + case OPTION: + case CONFIG_OPTION: if (!expression_allocate (expr, "parse_expression: OPTION")) log_fatal ("can't allocate expression"); - (*expr) -> op = expr_option; + (*expr) -> op = token == (OPTION + ? expr_option + : expr_config_option); + token = next_token (&val, cfile); (*expr) -> data.option = parse_option_name (cfile, 0); if (!(*expr) -> data.option) { *lose = 1; @@ -1775,6 +1915,14 @@ int parse_non_binary (expr, cfile, lose, context) (*expr) -> op = expr_leased_address; break; + case HOST_DECL_NAME: + token = next_token (&val, cfile); + if (!expression_allocate (expr, + "parse_expression: HOST_DECL_NAME")) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_host_decl_name; + break; + case PACKET: token = next_token (&val, cfile); if (!expression_allocate (expr, "parse_expression: PACKET")) @@ -2123,8 +2271,8 @@ int parse_expression (expr, cfile, lose, context, plhs, binop) would be painful to come up with BNF for it. However, it always starts as above and ends in a SEMI. */ -struct executable_statement *parse_option_statement (cfile, lookups, - option, op) +int parse_option_statement (result, cfile, lookups, option, op) + struct executable_statement **result; FILE *cfile; int lookups; struct option *option; @@ -2159,7 +2307,7 @@ struct executable_statement *parse_option_statement (cfile, lookups, parse_warn ("expecting a data expression."); skip_to_semi (cfile); } - return (struct executable_statement *)0; + return 0; } /* We got a valid expression, so use it. */ @@ -2182,7 +2330,7 @@ struct executable_statement *parse_option_statement (cfile, lookups, tmp, uniform, lookups)) { expression_dereference (&tmp, "parse_option_statement"); - return (struct executable_statement *)0; + return 0; } if (tmp) expression_dereference @@ -2200,15 +2348,14 @@ struct executable_statement *parse_option_statement (cfile, lookups, done: if (!parse_semi (cfile)) - return (struct executable_statement *)0; - stmt = ((struct executable_statement *) - dmalloc (sizeof *stmt, "parse_option_statement")); - memset (stmt, 0, sizeof *stmt); - stmt -> op = op; - if (expr && !option_cache (&stmt -> data.option, + return 0; + if (!executable_statement_allocate (result, "parse_option_statement")) + log_fatal ("no memory for option statement."); + (*result) -> op = op; + if (expr && !option_cache (&(*result) -> data.option, (struct data_string *)0, expr, option)) log_fatal ("no memory for option cache"); - return stmt; + return 1; } int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) diff --git a/common/tree.c b/common/tree.c index 6a247fcaa..466e4cbdf 100644 --- a/common/tree.c +++ b/common/tree.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: tree.c,v 1.32 1999/07/13 18:00:12 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +"$Id: tree.c,v 1.33 1999/07/16 21:33:59 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -538,6 +538,9 @@ int evaluate_boolean_expression (result, packet, options, lease, expr) case expr_encode_int32: case expr_binary_to_ascii: case expr_reverse: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: case expr_leased_address: log_error ("Data opcode in evaluate_boolean_expression: %d", expr -> op); @@ -651,6 +654,7 @@ int evaluate_data_expression (result, packet, options, lease, expr) /* Extract an option. */ case expr_option: + case expr_config_option: if (options) s0 = ((*expr -> data.option -> universe -> get_func) (result, expr -> data.option -> universe, @@ -1098,7 +1102,53 @@ int evaluate_data_expression (result, packet, options, lease, expr) #endif return 1; - + case expr_pick_first_value: + memset (&data, 0, sizeof data); + if ((evaluate_data_expression + (result, packet, options, lease, + expr -> data.pick_first_value.car))) { +#if defined (DEBUG_EXPRESSIONS) + log_info ("data: pick_first_value (%s, ???)", + print_hex_1 (result -> len, + result -> data, 40)); +#endif + return 1; + } + if ((evaluate_data_expression + (result, packet, options, lease, + expr -> data.pick_first_value.cdr))) { +#if defined (DEBUG_EXPRESSIONS) + log_info ("data: pick_first_value (NULL, %s)", + print_hex_1 (result -> len, + result -> data, 40)); +#endif + return 1; + } + +#if defined (DEBUG_EXPRESSIONS) + log_info ("data: pick_first_value (NULL, NULL) = NULL"); +#endif + return 0; + + case expr_host_decl_name: + if (!lease || !lease -> host) { + log_error ("data: host_decl_name: not available"); + return 0; + } + result -> len = strlen (lease -> host -> name) + 1; + if (buffer_allocate (&result -> buffer, result -> len, + "host-decl-name")) { + result -> data = &result -> buffer -> data [0]; + strcpy (&result -> data [0], lease -> host -> name); + result -> terminated = 1; + } else { + log_error ("data: host-decl-name: no memory."); + return 0; + } +#if defined (DEBUG_EXPRESSIONS) + log_info ("data: host-decl-name = %s", lease -> host -> name); +#endif + return 1; case expr_check: case expr_equal: @@ -1160,6 +1210,9 @@ int evaluate_numeric_expression (result, packet, options, lease, expr) case expr_encode_int32: case expr_binary_to_ascii: case expr_reverse: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: case expr_leased_address: log_error ("Data opcode in evaluate_numeric_expression: %d", expr -> op); @@ -1411,6 +1464,15 @@ void expression_dereference (eptr, name) name); break; + case expr_pick_first_value: + if (expr -> data.pick_first_value.car) + expression_dereference + (&expr -> data.pick_first_value.car, name); + if (expr -> data.pick_first_value.cdr) + expression_dereference + (&expr -> data.pick_first_value.cdr, name); + break; + case expr_reverse: if (expr -> data.reverse.width) expression_dereference (&expr -> data.reverse.width, @@ -1547,6 +1609,9 @@ static int op_val (op) case expr_known: case expr_binary_to_ascii: case expr_reverse: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: case expr_leased_address: return 100; @@ -1599,6 +1664,9 @@ enum expression_context op_context (op) case expr_known: case expr_binary_to_ascii: case expr_reverse: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: case expr_leased_address: return context_any; diff --git a/includes/dhcpd.h b/includes/dhcpd.h index b1fd6c7e8..6edf89412 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -186,6 +186,10 @@ struct lease { struct class *billing_class; struct hardware hardware_addr; + struct executable_statement *on_expiry; + struct executable_statement *on_commit; + struct executable_statement *on_release; + int flags; # define STATIC_LEASE 1 # define BOOTP_LEASE 2 @@ -902,11 +906,12 @@ struct option *parse_option_name PROTO ((FILE *, int)); void parse_option_space_decl PROTO ((FILE *)); int parse_option_code_definition PROTO ((FILE *, struct option *)); int parse_cshl PROTO ((struct data_string *, FILE *)); -struct executable_statement *parse_executable_statement PROTO ((FILE *, - int *)); -struct executable_statement *parse_executable_statements PROTO ((FILE *, - int *)); -struct executable_statement *parse_if_statement PROTO ((FILE *, int *)); +int parse_executable_statement PROTO ((struct executable_statement **, + FILE *, int *)); +int parse_executable_statements PROTO ((struct executable_statement **, + FILE *, int *)); +int parse_on_statement PROTO ((struct executable_statement **, FILE *, int *)); +int parse_if_statement PROTO ((struct executable_statement **, FILE *, int *)); int parse_boolean_expression PROTO ((struct expression **, FILE *, int *)); int parse_data_expression PROTO ((struct expression **, FILE *, int *)); int parse_numeric_expression PROTO ((struct expression **, FILE *, int *)); @@ -915,10 +920,8 @@ int parse_non_binary PROTO ((struct expression **, FILE *, int *, int parse_expression PROTO ((struct expression **, FILE *, int *, enum expression_context, struct expression **, enum expr_op)); -struct executable_statement *parse_option_statement PROTO ((FILE *, int, - struct option *, - enum statement_op) - ); +int parse_option_statement PROTO ((struct executable_statement **, FILE *, int, + struct option *, enum statement_op)); int parse_option_token PROTO ((struct expression **, FILE *, char *, struct expression *, int, int)); int parse_allow_deny PROTO ((struct option_cache **, FILE *, int)); @@ -1095,6 +1098,13 @@ int option_state_allocate PROTO ((struct option_state **, char *)); int option_state_reference PROTO ((struct option_state **, struct option_state *, char *)); int option_state_dereference PROTO ((struct option_state **, char *)); +int executable_statement_allocate PROTO ((struct executable_statement **, + char *)); +int executable_statement_reference PROTO ((struct executable_statement **, + struct executable_statement *, + char *)); +int executable_statement_dereference PROTO ((struct executable_statement **, + char *)); /* print.c */ char *print_hw_addr PROTO ((int, int, unsigned char *)); diff --git a/includes/dhctoken.h b/includes/dhctoken.h index b1e78a64a..203526cd5 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -184,6 +184,13 @@ enum dhcp_token { REVERSE = 402, LEASED_ADDRESS = 403, BINARY_TO_ASCII = 404, + PICK_FIRST_VALUE = 405, + CONFIG_OPTION = 406, + HOST_DECL_NAME = 407, + ON = 408, + EXPIRY = 409, + RELEASE = 410, + COMMIT = 411, }; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ diff --git a/includes/statement.h b/includes/statement.h index 1240e691d..f9c1660b1 100644 --- a/includes/statement.h +++ b/includes/statement.h @@ -21,6 +21,7 @@ */ struct executable_statement { + int refcnt; struct executable_statement *next; enum statement_op { if_statement, @@ -32,6 +33,8 @@ struct executable_statement { append_option_statement, prepend_option_statement, send_option_statement, + statements_statement, + on_statement, } op; union { struct { @@ -44,6 +47,11 @@ struct executable_statement { struct option_cache *supersede; struct option_cache *prepend; struct option_cache *append; + struct executable_statement *statements; + struct { + enum { expiry, commit, release } evtype; + struct executable_statement *statements; + } on; } data; }; diff --git a/includes/tree.h b/includes/tree.h index 964565bd9..b80066b4c 100644 --- a/includes/tree.h +++ b/includes/tree.h @@ -86,6 +86,9 @@ enum expr_op { expr_reverse, expr_leased_address, expr_binary_to_ascii, + expr_config_option, + expr_host_decl_name, + expr_pick_first_value, }; struct expression { @@ -107,6 +110,7 @@ struct expression { struct expression *len; } suffix; struct option *option; + struct option *config_option; struct { struct expression *offset; struct expression *len; @@ -129,6 +133,10 @@ struct expression { struct expression *width; struct expression *buffer; } reverse; + struct { + struct expression *car; + struct expression *cdr; + } pick_first_value; } data; int flags; # define EXPR_EPHEMERAL 1 diff --git a/server/confpars.c b/server/confpars.c index 5322260a0..6ee60900b 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: confpars.c,v 1.74 1999/07/12 22:44:16 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +"$Id: confpars.c,v 1.75 1999/07/16 21:34:14 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -426,10 +426,10 @@ int parse_statement (cfile, group, type, host_decl, declaration) } finish_option: - et = parse_option_statement - (cfile, 1, option, - supersede_option_statement); - if (!et) + et = (struct executable_statement *)0; + if (!parse_option_statement + (&et, cfile, 1, option, + supersede_option_statement)) return declaration; goto insert_statement; } else @@ -451,18 +451,16 @@ int parse_statement (cfile, group, type, host_decl, declaration) (unsigned char *)val, 0)); if (option) { token = next_token (&val, cfile); - et = parse_option_statement - (cfile, 1, option, - supersede_option_statement); - if (!et) + if (!parse_option_statement + (&et, cfile, 1, option, + supersede_option_statement)) return declaration; } } if (!et) { lose = 0; - et = parse_executable_statement (cfile, &lose); - if (!et) { + if (!parse_executable_statement (&et, cfile, &lose)) { if (!lose) { if (declaration) parse_warn ("expecting a %s.", @@ -483,13 +481,41 @@ int parse_statement (cfile, group, type, host_decl, declaration) } insert_statement: if (group -> statements) { + int multi = 0; + + /* If this set of statements is only referenced + by this group, just add the current statement + to the end of the chain. */ for (ep = group -> statements; ep -> next; ep = ep -> next) - ; - ep -> next = et; + if (ep -> refcnt > 1) /* XXX */ + multi = 1; + if (!multi) { + executable_statement_reference + (&ep -> next, et, "parse_statement"); + return declaration; + } + /* Otherwise, make a parent chain, and put the + current group statements first and the new + statement in the next pointer. */ + ep = (struct executable_statement *)0; + if (!executable_statement_allocate + (&ep, "parse_statement")) + log_fatal ("No memory for statements."); + ep -> op = statements_statement; + executable_statement_reference + (&ep -> data.statements, + group -> statements, "parse_statement"); + executable_statement_reference + (&ep -> next, et, "parse_statement"); + executable_statement_dereference + (&group -> statements, "parse_statement"); + executable_statement_reference + (&group -> statements, ep, "parse_statements"); } else - group -> statements = et; + executable_statement_reference + (&group -> statements, et, "parse_statements"); return declaration; }